Components
NumberField
Numeric input field with optional min, max, step, and increment/decrement stepper buttons
NumberField renders a labeled, accessible <input type="number"> connected to the active form adapter via context. It supports optional stepper buttons, min/max bounds, and custom step values. Error and hint states surface automatically — no prop wiring needed.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | — | Field name. Used as the form state key and to derive element IDs. |
label | string | — | Label text rendered above the input. | |
hint | string | — | Helper text shown below the input when no error is present. | |
placeholder | string | — | Placeholder text for the input. | |
min | number | — | Minimum allowed value. Clamps stepper decrement. | |
max | number | — | Maximum allowed value. Clamps stepper increment. | |
step | number | 1 | Increment/decrement step size. Also applied to native stepper arrows. | |
showStepper | boolean | false | Shows increment/decrement buttons. | |
disabled | boolean | false | Disables the input. Inherits from StackFormProvider if not set. | |
loading | boolean | false | Replaces the input with a skeleton shimmer. | |
required | boolean | false | Marks the field as required. Appends * to the label. | |
format | Intl.NumberFormatOptions | — | Number formatting options. Reserved — not applied to the native input in the current release. | |
classNames | NumberFieldClassNames | — | Tailwind class overrides per slot. Stacks with provider and core classes. | |
slots | NumberFieldSlots | — | Component overrides per slot. First non-null wins: field → provider → default. | |
slotProps | { wrapper?, label?, input?, error?, hint? } | — | Extra props passed to each slot. Field-level replaces provider-level per key. | |
onValueChange | (value: number) => void | — | Called after onChange with the new value. | |
validate | (value: number) => string | undefined | Promise<string | undefined> | — | Field-level validator. Runs on blur. |
Slots
| Slot | Prop interface | Description |
|---|---|---|
Wrapper | WrapperSlotProps | Outer container element |
Label | LabelSlotProps | Label element |
Input | NumberInputSlotProps | The <input type="number"> element |
Error | ErrorSlotProps | Error message |
Hint | HintSlotProps | Hint/helper text |
StepperIncrement | StepperButtonSlotProps | Increment button |
StepperDecrement | StepperButtonSlotProps | Decrement button |
classNames
| Key | Applied to |
|---|---|
wrapper | Outer container |
label | Label element |
input | Input element |
error | Error message |
hint | Hint text |
stepperIncrement | Increment button |
stepperDecrement | Decrement button |
Examples
With error
Errors surface automatically from the form adapter. Trigger one manually to test:
form.setError('price', { message: 'Price must be a valid number' })
<NumberField name="price" label="Price" />With hint
<NumberField
name="age"
label="Age"
hint="Enter your age in years."
min={0}
max={150}
/>With min, max, and stepper
<NumberField
name="quantity"
label="Quantity"
placeholder="1"
min={1}
max={100}
step={1}
showStepper
/>With step and hint
<NumberField
name="price"
label="Price (USD)"
placeholder="0.00"
step={0.01}
min={0}
hint="Enter price in dollars and cents."
/>With slot override
Replace the default increment/decrement buttons with custom components. Slot components receive only display-level props.
import type { StepperButtonSlotProps } from '@stackform/ui'
function StepButton({ direction, onClick, disabled, className }: StepperButtonSlotProps) {
return (
<button
type="button"
onClick={onClick}
disabled={disabled}
aria-label={direction === 'increment' ? 'Increase value' : 'Decrease value'}
className={className}
>
<span aria-hidden="true">{direction === 'increment' ? '+' : '−'}</span>
</button>
)
}
<NumberField
name="quantity"
label="Quantity"
min={0}
showStepper
slots={{ StepperIncrement: StepButton, StepperDecrement: StepButton }}
/>