Skip to content

NumberField

A number input with increment and decrement controls, formatting, validation, and compound slots.

Import

ts
import {
  NumberField,
  NumberFieldGroup,
  NumberFieldInput,
  NumberFieldIncrementButton,
  NumberFieldDecrementButton,
} from '@heroui-vue/vue'

Usage

Basic

<template>
  <NumberField class="demo-number-field-width" :default-value="1024" :min-value="0" name="width">
    <Label>Width</Label>
    <NumberFieldGroup>
      <NumberFieldDecrementButton />
      <NumberFieldInput class="demo-number-field-input" />
      <NumberFieldIncrementButton />
    </NumberFieldGroup>
  </NumberField>
</template>

<script setup lang="ts">
import { Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-width {
  width: 100%;
  max-width: 16rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

With Description

Enter the width in pixels
Value must be between 0 and 100

<template>
  <div class="demo-number-field-stack">
    <NumberField :default-value="1024" :min-value="0" name="width">
      <Label>Width</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Enter the width in pixels</Description>
    </NumberField>
    <NumberField
      :default-value="0.5"
      :format-options="{ style: 'percent' }"
      :max-value="1"
      :min-value="0"
      :step="0.1"
      name="percentage"
    >
      <Label>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Value must be between 0 and 100</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Required Field

Rate from 1 to 10

<template>
  <div class="demo-number-field-stack">
    <NumberField is-required :min-value="0" name="quantity">
      <Label is-required>Quantity</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
    </NumberField>
    <NumberField is-required :default-value="1" :max-value="10" :min-value="1" name="rating">
      <Label is-required>Rating</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Rate from 1 to 10</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Validation

Quantity must be greater than or equal to 0
Percentage must be between 0 and 100

<template>
  <div class="demo-number-field-stack">
    <NumberField is-invalid is-required :min-value="0" name="quantity" :value="-5">
      <Label is-invalid is-required>Quantity</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <FieldError>Quantity must be greater than or equal to 0</FieldError>
    </NumberField>
    <NumberField
      is-invalid
      :format-options="{ style: 'percent' }"
      :max-value="1"
      :min-value="0"
      name="percentage"
      :step="0.1"
      :value="1.5"
    >
      <Label is-invalid>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <FieldError>Percentage must be between 0 and 100</FieldError>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { FieldError, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Controlled

Current value: 1024

<template>
  <div class="demo-number-field-stack">
    <NumberField v-model="value" :min-value="0" name="width">
      <Label>Width</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Current value: {{ value }}</Description>
    </NumberField>
    <div class="demo-number-field-actions">
      <Button variant="tertiary" @click="value = 0">
        Reset to 0
      </Button>
      <Button variant="tertiary" @click="value = 2048">
        Set to 2048
      </Button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Button, Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'

const value = ref(1024)
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-actions {
  display: flex;
  gap: 0.5rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

With Validation

Enter a value between 0 and 100

<template>
  <div class="demo-number-field-stack">
    <NumberField
      v-model="value"
      is-required
      :format-options="{ style: 'percent' }"
      :is-invalid="isInvalid"
      :max-value="1"
      :min-value="0"
      name="percentage"
      :step="0.1"
    >
      <Label :is-invalid="isInvalid" is-required>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <FieldError v-if="isInvalid">Percentage must be between 0 and 100</FieldError>
      <Description v-else>Enter a value between 0 and 100</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { Description, FieldError, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'

const value = ref<number | undefined>()
const isInvalid = computed(() => value.value !== undefined && (value.value < 0 || value.value > 100))
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Step Values

Increments by 1
Increments by 5
Increments by 10

<template>
  <div class="demo-number-field-stack">
    <NumberField :default-value="0" :max-value="100" :min-value="0" name="step1" :step="1">
      <Label>Step: 1</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Increments by 1</Description>
    </NumberField>
    <NumberField :default-value="0" :max-value="100" :min-value="0" name="step5" :step="5">
      <Label>Step: 5</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Increments by 5</Description>
    </NumberField>
    <NumberField :default-value="0" :max-value="100" :min-value="0" name="step10" :step="10">
      <Label>Step: 10</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Increments by 10</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Format Options

Accounting format with EUR currency
Standard USD currency format
Percentage format (0-1, where 0.5 = 50%)
Decimal format with 2 decimal places
Unit format with kilograms

<template>
  <div class="demo-number-field-stack">
    <NumberField :default-value="99" :format-options="{ currency: 'EUR', currencySign: 'accounting', style: 'currency' }" :min-value="0" name="currency-eur">
      <Label>Currency (EUR - Accounting)</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Accounting format with EUR currency</Description>
    </NumberField>
    <NumberField :default-value="99.99" :format-options="{ currency: 'USD', style: 'currency' }" :min-value="0" name="currency-usd">
      <Label>Currency (USD)</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Standard USD currency format</Description>
    </NumberField>
    <NumberField :default-value="0.5" :format-options="{ style: 'percent' }" :max-value="1" :min-value="0" name="percentage" :step="0.01">
      <Label>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Percentage format (0-1, where 0.5 = 50%)</Description>
    </NumberField>
    <NumberField :default-value="1234.56" :format-options="{ maximumFractionDigits: 2, minimumFractionDigits: 2, style: 'decimal' }" :min-value="0" name="decimal">
      <Label>Decimal (2 decimal places)</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Decimal format with 2 decimal places</Description>
    </NumberField>
    <NumberField :default-value="1000" :format-options="{ style: 'unit', unit: 'kilogram', unitDisplay: 'short' }" :min-value="0" name="unit">
      <Label>Unit (Kilograms)</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Unit format with kilograms</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Custom Icons

Custom icon children

<template>
  <div class="demo-number-field-stack">
    <NumberField :default-value="1024" :min-value="0" name="width">
      <Label>Width (Custom Icons)</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton>
          <SearchMinusIcon />
        </NumberFieldDecrementButton>
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton>
          <SearchPlusIcon />
        </NumberFieldIncrementButton>
      </NumberFieldGroup>
      <Description>Custom icon children</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { defineComponent, h } from 'vue'
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'

const SearchMinusIcon = defineComponent({
  setup: () => () => h('svg', { height: 16, viewBox: '0 0 16 16', width: 16 }, [
    h('path', {
      d: 'M6.75 11a4.25 4.25 0 1 0 0-8.5 4.25 4.25 0 0 0 0 8.5m0 1.5a5.73 5.73 0 0 0 3.501-1.188l2.719 2.718a.75.75 0 1 0 1.06-1.06l-2.718-2.719A5.75 5.75 0 1 0 6.75 12.5m-2-6.5a.75.75 0 0 0 0 1.5h4a.75.75 0 0 0 0-1.5z',
      fill: 'currentColor',
      'fill-rule': 'evenodd',
    }),
  ]),
})

const SearchPlusIcon = defineComponent({
  setup: () => () => h('svg', { height: 16, viewBox: '0 0 16 16', width: 16 }, [
    h('path', {
      d: 'M6.75 11a4.25 4.25 0 1 0 0-8.5 4.25 4.25 0 0 0 0 8.5m0 1.5a5.73 5.73 0 0 0 3.501-1.188l2.719 2.718a.75.75 0 1 0 1.06-1.06l-2.718-2.719A5.75 5.75 0 1 0 6.75 12.5m.75-7.75a.75.75 0 0 0-1.5 0V6H4.75a.75.75 0 0 0 0 1.5H6v1.25a.75.75 0 0 0 1.5 0V7.5h1.25a.75.75 0 0 0 0-1.5H7.5z',
      fill: 'currentColor',
      'fill-rule': 'evenodd',
    }),
  ]),
})
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

With Chevrons

<template>
  <NumberField
    class="demo-number-field-width"
    :default-value="99"
    :format-options="{ currency: 'EUR', currencySign: 'accounting', style: 'currency' }"
    :min-value="0"
    name="amount"
  >
    <Label>Number field with chevrons</Label>
    <NumberFieldGroup class="demo-number-field-chevron-group">
      <NumberFieldInput />
      <div class="demo-number-field-chevron-buttons">
        <NumberFieldIncrementButton class="demo-number-field-chevron-button">
          <ChevronUpIcon />
        </NumberFieldIncrementButton>
        <NumberFieldDecrementButton class="demo-number-field-chevron-button">
          <ChevronDownIcon />
        </NumberFieldDecrementButton>
      </div>
    </NumberFieldGroup>
  </NumberField>
</template>

<script setup lang="ts">
import { defineComponent, h } from 'vue'
import { Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'

const ChevronUpIcon = defineComponent({
  setup: () => () => h('svg', { 'aria-hidden': 'true', height: 11, viewBox: '0 0 16 16', width: 11 }, [
    h('path', {
      d: 'M13.03 10.53a.75.75 0 0 1-1.06 0L8 6.56l-3.97 3.97a.75.75 0 1 1-1.06-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1 0 1.06',
      fill: 'currentColor',
      'fill-rule': 'evenodd',
    }),
  ]),
})

const ChevronDownIcon = defineComponent({
  setup: () => () => h('svg', { 'aria-hidden': 'true', height: 11, viewBox: '0 0 16 16', width: 11 }, [
    h('path', {
      d: 'M2.97 5.47a.75.75 0 0 1 1.06 0L8 9.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06',
      fill: 'currentColor',
      'fill-rule': 'evenodd',
    }),
  ]),
})
</script>

<style lang="less">
.demo-number-field-width {
  width: 100%;
  max-width: 16rem;
}

.demo-number-field-chevron-group {
  grid-template-columns: 1fr 1.5rem;
}

.demo-number-field-chevron-buttons {
  display: flex;
  height: calc(100% + 2px);
  flex-direction: column;
  border-left: 1px solid color-mix(in oklab, var(--color-field-placeholder) 15%, transparent);
}

.demo-number-field-chevron-button {
  width: 1.5rem;
  height: 50%;
  min-height: 0;
  flex: 1;
  border-right: 0;
  border-left: 0;
  border-radius: 0;
  padding: 0;
}
</style>

Disabled State

Enter the width in pixels
Value must be between 0 and 100

<template>
  <div class="demo-number-field-stack">
    <NumberField is-disabled :default-value="1024" :min-value="0" name="width">
      <Label is-disabled>Width</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Enter the width in pixels</Description>
    </NumberField>
    <NumberField
      is-disabled
      :default-value="0.5"
      :format-options="{ style: 'percent' }"
      :max-value="1"
      :min-value="0"
      name="percentage"
      :step="0.1"
    >
      <Label is-disabled>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Value must be between 0 and 100</Description>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  width: 100%;
  max-width: 16rem;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Full Width

<template>
  <div class="demo-number-field-full">
    <NumberField full-width :default-value="1024" :min-value="0" name="width">
      <Label>Width</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-full {
  width: 400px;
}
</style>

Variants

<template>
  <div class="demo-number-field-stack">
    <NumberField :default-value="100" :min-value="0" name="primary-width" variant="primary">
      <Label>Primary variant</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
    </NumberField>
    <NumberField :default-value="100" :min-value="0" name="secondary-width" variant="secondary">
      <Label>Secondary variant</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
    </NumberField>
  </div>
</template>

<script setup lang="ts">
import { Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-stack {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

In Surface

Enter the width in pixels
Value must be between 0 and 100

<template>
  <Surface class="demo-number-field-surface">
    <NumberField :default-value="1024" :min-value="0" name="width" variant="secondary">
      <Label>Width</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Enter the width in pixels</Description>
    </NumberField>
    <NumberField
      :default-value="0.5"
      :format-options="{ style: 'percent' }"
      :max-value="1"
      :min-value="0"
      name="percentage"
      :step="0.1"
      variant="secondary"
    >
      <Label>Percentage</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <Description>Value must be between 0 and 100</Description>
    </NumberField>
  </Surface>
</template>

<script setup lang="ts">
import { Description, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput, Surface } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-surface {
  display: flex;
  width: 100%;
  max-width: 280px;
  flex-direction: column;
  gap: 1rem;
  border-radius: 1.5rem;
  padding: 1.5rem;
}
</style>

Form Example

Only 3 items available

<template>
  <form class="demo-number-field-form" @submit.prevent="handleSubmit">
    <NumberField
      v-model="value"
      is-required
      :is-invalid="isOutOfStock"
      :max-value="5"
      :min-value="1"
      name="quantity"
    >
      <Label :is-invalid="isOutOfStock" is-required>Order quantity</Label>
      <NumberFieldGroup>
        <NumberFieldDecrementButton />
        <NumberFieldInput class="demo-number-field-input" />
        <NumberFieldIncrementButton />
      </NumberFieldGroup>
      <FieldError v-if="isOutOfStock">Only {{ stockAvailable }} items left in stock</FieldError>
      <Description v-else>Only {{ stockAvailable }} items available</Description>
    </NumberField>
    <Button class="demo-number-field-submit" :is-disabled="!canSubmit" :is-pending="isSubmitting" type="submit" variant="primary">
      <Spinner v-if="isSubmitting" color="current" size="sm" />
      {{ isSubmitting ? 'Processing...' : 'Place Order' }}
    </Button>
  </form>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { Button, Description, FieldError, Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput, Spinner } from '@heroui-vue/vue'

const stockAvailable = 3
const value = ref<number | undefined>()
const isSubmitting = ref(false)
const isOutOfStock = computed(() => value.value !== undefined && value.value > stockAvailable)
const canSubmit = computed(() => value.value !== undefined && value.value >= 1 && value.value <= stockAvailable)

const handleSubmit = () => {
  if (!canSubmit.value) return

  isSubmitting.value = true
  window.setTimeout(() => {
    value.value = undefined
    isSubmitting.value = false
  }, 1200)
}
</script>

<style lang="less">
.demo-number-field-form {
  display: flex;
  width: 280px;
  flex-direction: column;
  gap: 1rem;
}

.demo-number-field-input {
  width: 120px;
}

.demo-number-field-submit {
  width: 100%;
}
</style>

Custom Render Function

<template>
  <NumberField class="demo-number-field-width" data-custom="foo" :default-value="1024" :min-value="0" name="width">
    <Label>Width</Label>
    <NumberFieldGroup>
      <NumberFieldDecrementButton />
      <NumberFieldInput class="demo-number-field-input" />
      <NumberFieldIncrementButton />
    </NumberFieldGroup>
  </NumberField>
</template>

<script setup lang="ts">
import { Label, NumberField, NumberFieldDecrementButton, NumberFieldGroup, NumberFieldIncrementButton, NumberFieldInput } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-number-field-width {
  width: 100%;
  max-width: 16rem;
}

.demo-number-field-input {
  width: 120px;
}
</style>

Styling

NumberField owns the value and state attributes. NumberFieldGroup, NumberFieldInput, and the increment/decrement buttons map to the React source CSS slots. Demo-only widths and layout classes are included in each source panel.

CSS Classes

ClassDescription
.number-fieldRoot field
.number-field__groupInput and button group
.number-field__inputText input
.number-field__increment-buttonIncrement control
.number-field__decrement-buttonDecrement control

API

Props

PropTypeDefaultDescription
modelValuenumberundefinedControlled value for v-model
defaultValuenumberundefinedInitial uncontrolled value
minValuenumberundefinedMinimum value used by step buttons
maxValuenumberundefinedMaximum value used by step buttons
stepnumber1Increment/decrement step
formatOptionsIntl.NumberFormatOptionsundefinedDisplay formatting options
isInvalidbooleanfalseInvalid state
isDisabledbooleanfalseDisabled state
isRequiredbooleanfalseRequired state
fullWidthbooleanfalseFill container width
variant'primary' \| 'secondary''primary'Visual variant

Events

EventPayloadDescription
update:modelValuenumber \| undefinedEmits when value changes
changenumber \| undefinedEmits when value changes

Released under the Apache-2.0 License.