Number Input
A bordered numeric input with a non-interactive up/down cue in the trailing area — stepping is keyboard-only. The form-friendly sibling of NumberField.
Installation
Usage
NumberInput is the classic bordered numeric field: an InputGroup shell, optional prefix / suffix, and a non-interactive up/down cue in the trailing area (suffix replaces the cue when set). Stepping is keyboard-only — ArrowUp / ArrowDown on the focused input. For clickable Minus / Plus steppers use NumberField.
"use client";
import { NumberInput } from "@/ui";
export default function Demo() {
return (
<div className="flex w-full max-w-md flex-col gap-4">
<NumberInput defaultValue={2026} thousands prefix="$" suffix="USD" aria-label="Amount in US dollars" />
<NumberInput defaultValue={5} min={0} max={100} step={5} thousands aria-label="Quantity" />
<NumberInput defaultValue={3.14} step={0.01} thousands placeholder="0.00" aria-label="Price" />
<NumberInput defaultValue={5} positiveInteger indicator={false} aria-label="Count" />
</div>
);
}
Custom
The cue, thousands separators and prefix/suffix are composite features. For a fully custom panel, combine InputGroup, NumberRoot and plain content, driving the value yourself.
Assemble from Input parts
The stepping cue, thousands separators and prefix/suffix are composite features. For a fully custom panel, combine InputGroup, NumberRoot and plain content, driving the value yourself.
"use client";
import { InputGroup, NumberRoot } from "@/ui";
export default function Demo() {
return (
<div className="w-full max-w-md rounded-lg border bg-muted/40 p-4">
<p className="mb-3 text-sm font-medium">Assemble from Input parts</p>
<p className="mb-3 text-sm text-muted-foreground">
The stepping cue, thousands separators and prefix/suffix are composite features.
For a fully custom panel, combine <code className="rounded bg-muted px-1 py-0.5 text-xs">InputGroup</code>,{" "}
<code className="rounded bg-muted px-1 py-0.5 text-xs">NumberRoot</code> and plain
content, driving the value yourself.
</p>
<InputGroup className="max-w-3xs">
<span className="pr-1 text-sm text-muted-foreground">Qty</span>
<NumberRoot defaultValue="1" inputMode="numeric" aria-label="Quantity" />
<span className="pr-1 text-sm text-muted-foreground">pcs</span>
</InputGroup>
</div>
);
}
API Reference
NumberInput
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | number | string | - | Initial value (uncontrolled mode) |
value | number | string | undefined | - | Current value (controlled mode) |
onValueChange | (value?: number) => void | (value?: string) => void | - | Value change handler. Returns number | undefined when positiveInteger=true, otherwise string |
invalid | boolean | - | Whether the field is in an invalid state |
min | number | 0 (positiveInteger) or -Infinity | Minimum allowed value |
max | number | Infinity | Maximum allowed value |
step | number | 1 | Step size for ArrowUp / ArrowDown |
positiveInteger | boolean | false | Restrict to positive integers only. Changes value type to number | undefined |
prefix | React.ReactNode | - | Content rendered before the number (e.g. a currency symbol) |
suffix | React.ReactNode | - | Content rendered after the number — replaces the stepping cue when set |
thousands | boolean | false | Group the integer part with thousands separators while the input is not focused; the committed value stays unformatted |
indicator | boolean | true | Show the non-interactive up/down cue in the trailing area (no effect while a suffix is set) |
className | ClassNameValue | - | Custom classes, applied to the group shell |
style | React.CSSProperties | - | Inline styles, applied to the group shell |
classNames | { leading?; trailing?; root? } — each ClassNameValue | - | Custom classes for the prefix/suffix slots and the inner input (root) |
styles | { leading?; trailing?; root? } — each React.CSSProperties | - | Inline styles for the prefix/suffix slots and the inner input (root) |
disabled | boolean | false | Disable the entire field |
...props | React.ComponentProps<"input"> | - | Supports all native input props (except type, className), such as onBlur |
Number Field
A compact numeric field with a leading Minus and trailing Plus stepper button — keyboard stepping, thousands separators and a border by default.
Pager
A controlled single-DOM pager with touch gesture dragging, loop and View-Transition page switching, built for manga-style readers and paged content