NumberField
Numeric input with increment/decrement buttons, drag-to-scrub, and locale-aware formatting. Supports currency, percent, and unit display via Intl.NumberFormat.
Usage
NumberField renders a spinbutton input with optional increment, decrement, and scrub controls. Wire it up with v-model for two-way binding.
Anatomy
<script setup lang="ts">
import { NumberField } from '@vuetify/v0'
</script>
<template>
<NumberField.Root>
<NumberField.Scrub />
<NumberField.Description />
<NumberField.Decrement />
<NumberField.Control />
<NumberField.Increment />
<NumberField.Error />
</NumberField.Root>
</template>Architecture
Root composes createNumberField which delegates to createInput for field state and createNumeric for math operations. Each sub-component consumes the root context.
Examples
6 items in cart. Each quantity clamps to its line's stock — the out-of-stock cap is disabled at zero.
Recipes
Spin-on-Hold
Increment and Decrement buttons repeat automatically when held. Configure timing with spin-delay (initial pause, default 400ms) and spin-rate (repeat interval, default 60ms):
<template>
<NumberField.Root :spin-delay="300" :spin-rate="40">
<NumberField.Decrement>-</NumberField.Decrement>
<NumberField.Control />
<NumberField.Increment>+</NumberField.Increment>
</NumberField.Root>
</template>Mouse Wheel
Enable value adjustment via scroll wheel when the input is focused:
<template>
<NumberField.Root v-model="value" wheel>
<NumberField.Control />
</NumberField.Root>
</template>Data Attributes
Style interactive states without slot props:
| Attribute | Values | Components |
|---|---|---|
data-state | valid, invalid, pristine | Root, Control |
data-dirty | true | Root |
data-focused | true | Root, Control |
data-disabled | true | Root, Control, Increment, Decrement, Scrub |
data-readonly | true | Root, Control, Scrub |
Accessibility
NumberField.Control renders with role="spinbutton" and full ARIA attributes per the WAI-ARIA Spinbutton pattern↗︎.
ARIA Attributes
| Attribute | Value | Notes |
|---|---|---|
role | spinbutton | Applied to Control |
aria-valuenow | Current value | undefined when empty |
aria-valuemin | Min value | Only when finite |
aria-valuemax | Max value | Only when finite |
aria-valuetext | Formatted string | Screen readers announce “$42.00” not “42” |
aria-invalid | true | When validation fails |
aria-label | Label text | From Root’s label prop |
aria-describedby | Description ID | When Description is mounted |
aria-errormessage | Error ID | When Error is mounted with messages |
aria-required | true | When Root has required |
Increment and Decrement buttons use tabindex="-1" to keep them out of the tab sequence — only the Input is focusable.
Keyboard Navigation
| Key | Action |
|---|---|
ArrowUp | Increment by one step |
ArrowDown | Decrement by one step |
Shift+ArrowUp | Increment by 10 steps |
Shift+ArrowDown | Decrement by 10 steps |
PageUp | Increment by leap (default step × 10) |
PageDown | Decrement by leap (default step × 10) |
Home | Set to minimum |
End | Set to maximum |
Enter | Commit the typed value |
FAQ
Root accepts a locale prop (BCP 47 tag, defaults to en-US) and a format prop with Intl.NumberFormatOptions. While the input is focused it shows the raw number for editing; on blur it displays the formatted string. Parsing strips locale-specific group separators and currency symbols automatically.
On blur, the Input parses the text via parse(). If the result is NaN, the value becomes null. If clamp is true (default), the value is clamped to min/max and snapped to the nearest step.
Scrub accepts a sensitivity prop (default 1) that controls how many pixels of horizontal movement equal one step. Higher values require more movement per step for finer control.
Yes. Only Root and Input are required. Buttons, Scrub, Description, and Error are all optional.