Input Number
Numeric input with increment/decrement controls, min/max/step, and format options.
Examples
Stepper with bounds
Increment/decrement controls plus min, max, and step keep input valid.
Use the steppers or type — clamped to 0–99.
import { InputNumber, InputNumberField, InputNumberStepper } from "@codefast/ui/input-number";
import { Label } from "@codefast/ui/label";
export function InputNumberQuantity() {
return (
<div className="grid w-full max-w-xs gap-1.5">
<Label htmlFor="qty">Quantity</Label>
<InputNumber id="qty" defaultValue={1} min={0} max={99}>
<InputNumberField />
<InputNumberStepper />
</InputNumber>
<p className="text-xs text-ui-muted">Use the steppers or type — clamped to 0–99.</p>
</div>
);
}
Formats & layouts
Format as currency with Intl options, or flank the field for a split layout.
import {
InputNumber,
InputNumberDecrement,
InputNumberField,
InputNumberIncrement,
InputNumberStepper,
} from "@codefast/ui/input-number";
import { Label } from "@codefast/ui/label";
export function InputNumberFormats() {
return (
<div className="grid w-full max-w-xs gap-4">
<div className="grid gap-1.5">
<Label htmlFor="price">Price</Label>
<InputNumber
id="price"
defaultValue={9.99}
min={0}
step={0.01}
formatOptions={{ style: "currency", currency: "USD" }}
>
<InputNumberField />
<InputNumberStepper />
</InputNumber>
</div>
<div className="grid gap-1.5">
<Label htmlFor="cart">Cart quantity (split)</Label>
<InputNumber id="cart" defaultValue={2} min={0} max={10}>
<InputNumberDecrement />
<InputNumberField className="text-center" />
<InputNumberIncrement />
</InputNumber>
</div>
</div>
);
}
Disabled & invalid
Native disabled plus aria-invalid styling.
Must be 100 or less.
import { InputNumber, InputNumberField, InputNumberStepper } from "@codefast/ui/input-number";
import { Label } from "@codefast/ui/label";
export function InputNumberStates() {
return (
<div className="grid w-full max-w-xs gap-4">
<div className="grid gap-1.5">
<Label htmlFor="in-disabled">Disabled</Label>
<InputNumber id="in-disabled" defaultValue={5} disabled>
<InputNumberField />
<InputNumberStepper />
</InputNumber>
</div>
<div className="grid gap-1.5">
<Label htmlFor="in-invalid">Invalid</Label>
<InputNumber id="in-invalid" defaultValue={150} min={0} max={100}>
<InputNumberField aria-invalid />
<InputNumberStepper />
</InputNumber>
<p className="text-xs text-rose-500">Must be 100 or less.</p>
</div>
</div>
);
}
Usage
The minimal import and composition — see Examples below for styled, real-world variants.
import { InputNumber, InputNumberField, InputNumberStepper } from "@codefast/ui/input-number";
export function InputNumberUsage() {
return (
<InputNumber defaultValue={1}>
<InputNumberField />
<InputNumberStepper />
</InputNumber>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Composable parts — pair InputNumberField with InputNumberStepper for the stacked layout, or flank it with InputNumberDecrement and InputNumberIncrement for a split layout. Layout follows child order.
- formatOptions (Intl.NumberFormatOptions) formats the displayed value, e.g. currency or percent, while the underlying value stays a plain number.
- min/max/step clamp both typed and stepper-driven changes to a valid range, and only the button facing a bound is disabled.
- Built-in loading/spinner support, e.g. while a computed value is being fetched.
API reference
Props for each part of the component. All native element props are also forwarded.
InputNumber
The container that owns the numeric state, bounds, and formatting. Compose the parts below as children.
valuenumberThe controlled numeric value. Or use defaultValue uncontrolled.
onChange(value?: number) => voidCalled with the parsed number, or undefined when the field is cleared.
minnumberThe lower bound. Values are clamped to the range.
maxnumberThe upper bound. Values are clamped to the range.
stepnumberThe increment applied by the steppers.
Default
1formatOptionsIntl.NumberFormatOptionsFormat the display, e.g. { style: "currency", currency: "USD" }.
InputNumberField
The editable spinbutton input.
aria-invalidbooleanMarks the field invalid and drives the container's invalid styling.
InputNumberStepper
A stacked chevron column with both increment and decrement controls — the default layout. Place it after the field.
classNamestringCompose the column's styling.
InputNumberDecrement
A standalone decrement button for the split layout. Place it before the field.
childrenReactNodeOverride the default minus icon.
InputNumberIncrement
A standalone increment button for the split layout. Place it after the field.
childrenReactNodeOverride the default plus icon.
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
| Key | Function |
|---|---|
| Arrow+Up | Increments by one step. |
| Arrow+Down | Decrements by one step. |
- Renders a spinbutton with aria-valuenow / valuemin / valuemax.
- Pair with a Label so the field has an accessible name.
- Formatting is display-only — the underlying value stays numeric.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Set min, max, and step to express the valid range.
- Use formatOptions for currency, percent, and units.
Don’t
- Don’t use it for codes or phone numbers — use Input.
- Don’t omit a label.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.