NumberField

4 parts

A numeric input with stepper controls, keyboard increment/decrement, and optional clamping. The interactive root: it owns the value (controlled via v-model / update:modelValue or uncontrolled via defaultValue), clamps to min/max, snaps to step, formats with the active locale, and provides context to NumberFieldInput, NumberFieldIncrement, and NumberFieldDecrement. Use it whenever you need a styled number entry with spinner buttons and arrow-key support.

Demo

Loading demo…

Anatomy

Import the parts and compose them. Each part forwards attributes to its underlying element.

vue
import {
  NumberFieldDecrement,
  NumberFieldIncrement,
  NumberFieldInput,
  NumberFieldRoot,
} from '@robonen/primitives/forms/number-field';

<NumberFieldRoot>
  <NumberFieldDecrement />
  <NumberFieldIncrement />
  <NumberFieldInput />
</NumberFieldRoot>

API Reference

NumberFieldDecrement

Decrement

A button that decreases the value by one `step`. Rendered as a `<button>` by default, kept out of the tab order (the input is the focusable spinbutton) but exposed to assistive tech with an `aria-label`. Holding the button auto-repeats the decrement, and it is disabled when the root is `disabled`/`readonly`, when its own `disabled` prop is set, or when the value is already at `min`.

PropTypeDescription
disabled?booleanDisable this button independently of the root.
ariaLabel?stringAccessible label for assistive tech. Bind via aria-label (Vue maps the kebab-case attribute to this prop).

NumberFieldIncrement

Increment

A button that increases the value by one `step`. Rendered as a `<button>` by default, kept out of the tab order (the input is the focusable spinbutton) but exposed to assistive tech with an `aria-label`. Holding the button auto-repeats the increment, and it is disabled when the root is `disabled`/`readonly`, when its own `disabled` prop is set, or when the value is already at `max`.

PropTypeDescription
disabled?booleanDisable this button independently of the root.
ariaLabel?stringAccessible label for assistive tech. Bind via aria-label (Vue maps the kebab-case attribute to this prop).

NumberFieldInput

Input

The text field that displays and edits the value, rendered as a native `<input role="spinbutton">` wired to the root context. It parses typed input, mirrors the current value via `aria-valuenow`/`aria-valuemin`/`aria-valuemax`, and handles Arrow/Page/Home/End keys to step, jump, or clamp to the bounds. Mouse-wheel scrolling steps the value while focused, keystrokes that would produce an invalid number are rejected, and the value is re-clamped, snapped, and reformatted on blur or Enter.

PropTypeDescription
placeholder?string
name?string
required?boolean

NumberFieldRoot

Root

A numeric input with stepper controls, keyboard increment/decrement, and optional clamping. The interactive root: it owns the value (controlled via `v-model` / `update:modelValue` or uncontrolled via `defaultValue`), clamps to `min`/`max`, snaps to `step`, formats with the active locale, and provides context to `NumberFieldInput`, `NumberFieldIncrement`, and `NumberFieldDecrement`. Use it whenever you need a styled number entry with spinner buttons and arrow-key support.

PropTypeDescription
defaultValue?number | null
min?number
max?number
step?number
stepSnapping?booleanWhen false, values are clamped but not snapped to the nearest step.
disabled?boolean
readonly?boolean
name?stringNative input name; submits the value with the surrounding <form>.
required?booleanMark the field required so native form validation fires on empty submit.
formatOptions?Intl.NumberFormatOptionsIntl.NumberFormat options controlling display and the allowed characters.
locale?stringLocale override for formatting/parsing; falls back to the app ConfigProvider.
disableWheelChange?booleanWhen false, wheel scrolling over the input does not change the value.
invertWheelChange?booleanInvert the direction of wheel-driven stepping.
focusOnChange?booleanWhen true (default), stepper buttons return focus to the input.
modelValue?number | nullTwo-way bound value (v-model).
Emits
EventPayload
update:modelValue[value: number | null]