Number Field
A number input with stepper buttons for adjusting the value.
Usage
NumberField folds the decrement button, text input, and increment button into one control — you render a single <NumberField />, not a set of parts. It accepts only numeric input, steps with the buttons or the ↑/↓ arrow keys, and reformats the value when you commit. Use it uncontrolled with defaultValue, or controlled with value + onValueChange.
Unlike a checkbox or radio, the input is a real text field, so give it a label the usual way — an external <label htmlFor> pointing at the field's id, or an aria-label. The rolling-digit animation on stepper presses is skipped when the user prefers reduced motion.
Examples
Variants
variant switches the appearance between a bordered outline (default) and a filled soft field. The stepper buttons invert their fill so they stay legible against either.
Sizes
size scales the field width, steppers, and text together — sm, md (default), or lg.
Min, max & step
min and max clamp the value and disable the stepper once a bound is reached; clearing the field and blurring snaps back to min (or 0). step sets how far each press or arrow key moves the value — hold Shift for largeStep (10× by default) or Alt for smallStep.
Formatting
Pass format — an Intl.NumberFormatOptions object — and an optional locale to display the value as currency, a percentage, units, and the like. The display reformats while the underlying value stays a plain number.
Controlled
Drive the value yourself with value + onValueChange. The handler receives null when the field is empty, so coalesce before using the number.
Disabled & error states
disabled greys out the field and both steppers and blocks interaction. Set aria-invalid to paint the error state — it's mirrored to data-invalid on the field and its steppers. Wrapping the field in a Field marked invalid produces the same styling and is the better choice when you're also rendering a validation message.
RTL
Every Appica UI component supports right-to-left layouts out of the box. Set the dir attribute on a container (commonly your <html> element) so CSS logical properties resolve correctly, and wrap your tree in DirectionProvider so direction-aware behavior — roving focus, popup placement, and the like — follows the same direction.
The decrement and increment steppers swap sides to follow the resolved direction, and a matching locale formats the value with that locale's own digits. For setup details and caveats, see the RTL guide.
API reference
A single control. The variant, size, placeholder, and inputProps props are Appica additions; every other prop is forwarded to Base UI's NumberField.Root.
NumberField wraps Base UI's NumberField (Root, Input, Increment, Decrement) and forwards every remaining Root prop. It exposes data-* state attributes (data-disabled, data-readonly, data-invalid, data-scrubbing, …) on the field and its parts for styling — see the Base UI docs for the full surface. When placed inside a Base UI Field.Root marked invalid, the error state (data-invalid) propagates to the input and both steppers automatically.
Accessibility
- The inner element is a real
<input>withrole="spinbutton", exposingaria-valuenow,aria-valuemin, andaria-valuemaxto assistive tech. - Give the field an accessible name — an external
<label htmlFor>pointing at itsid, or anaria-label. - The steppers are real
<button>s labelled Increase value / Decrease value, and becomedisabledat a bound or when the field is disabled. - ↑/↓ step the value (with Shift/Alt for the large/small step), and typing accepts only valid numeric input.
disabledblocks all interaction;readOnlykeeps the field focusable but inert.aria-invalidis bridged todata-invalidso the error state can be styled without a wrappingField.- The rolling-digit animation on stepper presses honours
prefers-reduced-motion.