Number Field
Text Field's exact label/ description/error scaffold around a real <input type="number"> instead of type="text" — a numeric keypad on mobile, native min/max/step constraint validation, and native ↑/↓ stepping while focused, all for free. The up/down buttons beside it don't reimplement stepping: they call the input's own native stepUp()/stepDown() and read .value back afterward, since those methods change the value without dispatching an event. They're excluded from the tab order — focused arrow keys already do the identical thing natively, so a keyboard-only flow never needs to reach them.
Playground
Toggle every adjustable prop and watch the component — and the code — update live.
How many would you like?
Usage
<NumberField label="Quantity" defaultValue={1} min={0} max={10} description="How many would you like?" errorMessage="Enter a value between 0 and 10." /><kernel-number-field label="Quantity" value="1" min="0" max="10" description="How many would you like?" error-message="Enter a value between 0 and 10."></kernel-number-field>Props
| Prop | Type | Default |
|---|---|---|
label | ReactNode (required) | — |
hideLabel | boolean | false |
value | number | — |
defaultValue | number | — |
min | number | — |
max | number | — |
step | number | 1 |
description | ReactNode | — |
errorMessage | ReactNode | — |
invalid | boolean | false |
size | "sm" | "md" | "lg" | "md" |
Typing "-", "1.", or an empty field are all valid states a browser lets you type on the way to a real number — like Color Picker's hex field, the displayed text is a local draft that only commits back to the real numeric value once it actually parses, so mid-typing states are never rejected or reformatted out from under you.
Accessibility
- The stepper buttons are real
<button>elements but excluded from the Tab sequence (tabIndex={-1}) since focused ↑/↓ already steps the value natively — an intentional tradeoff, not an oversight, mirroring the same reasoning behind Tag Input's remove buttons. - The native spinner arrows are hidden since these buttons replace them; there's never a second, competing stepper on screen.
aria-invalidand:user-invalidboth work natively with no extra ARIA wiring.