Forms
Number input
A numeric field that behaves.
Import
import { NumberInput } from '@the_viveksingh/vivek-ui'A numeric field that behaves
Deliberately not type="number": no wheel-drift while scrolling, no per-browser e/- juggling, and garbage cannot read back as an empty string. The value is number | null - null is empty, NaN never escapes - and drafts commit on Enter or blur, clamped into range.
Arrows step, Shift+arrow steps by 10, Home/End jump to the bounds. Scrolling the page never changes it.
2 seats at $12 = $24
precision={2} rounds every commit; step works in decimals.
const [qty, setQty] = useState<number | null>(2)
<NumberInput
value={qty}
onValueChange={setQty}
min={1}
max={50}
/>
// ArrowUp/Down step - Shift steps by 10 - Home/End jump to the bounds.
// The steppers are pointer-only chrome: the input itself is the spinbutton.Decimals, rounded on commit
precision fixes the decimal places; step works in fractions.
<NumberInput defaultValue={4.5} step={0.25} precision={2} min={0} />
// Opt back into wheel-to-step only when you mean it:
<NumberInput allowMouseWheel defaultValue={10} />Props
Generated from the package's own type declarations, so this table cannot drift from the code.
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | null | — | Controlled value. `null` is "empty" — never `NaN`, which poisons every comparison. |
defaultValue | number | null | — | — |
onValueChange | (value: number | null) => void | — | — |
min | number | — | — |
max | number | — | — |
step | number | — | Increment applied by the steppers and the arrow keys. Default `1`. |
precision | number | — | Decimal places the committed value is rounded to. Unset = no rounding. |
size | 'sm' | 'md' | 'lg' | — | — |
invalid | boolean | — | — |
clampOnBlur | boolean | — | Clamp into `[min, max]` when focus leaves. Default `true` — the alternative is a field that looks settled while holding a value the range forbids. |
allowMouseWheel | boolean | — | Let the mouse wheel change the value while the field is focused. Default `false`: a page scroll drifting a focused quantity is the classic silent-corruption bug in `type="number"`, and opting back in should be a decision, not an accident. |
Every remaining prop is spread onto the root element, so all standard HTML and ARIA attributes work. className and style are merged with the library's own, never replaced, and the ref forwards to the root DOM node.
Rendering
NumberInput declares 'use client' because it needs state, effects or event handlers. Importing it into a Server Component creates a client boundary at this component — everything above it stays on the server.