NumberField

A numeric input with caret steppers, a unit suffix and min/max clamping. For quantities, prices and counts.

NumberField playground

users

Install NumberField

1. New project? One command installs the package and wires everything - see Installation:

bash
pnpm dlx zyncat-ui init

2. Import the component - it loads its own stylesheet:

tsx
import { NumberField } from '@zyncat/ui/number-field';

Usage

tsx
import { NumberField } from '@zyncat/ui/number-field';
 
<NumberField label="Seats" unit="users" min={1} max={50} value={seats} onChange={setSeats} />

Compose NumberField in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.

NumberField props

NumberField

PropTypeDefaultDescription
...htmlAttributesHTMLAttributes—Standard <input> attributes (name, aria-*, ...) forwarded to the input.
unitstring—Unit suffix shown inside the field (e.g. "days", "%").
minnumber0Minimum value - steps and committed typing clamp up to this; the decrease stepper disables here.
maxnumberInfinityMaximum value - steps and committed typing clamp down to this; the increase stepper disables here.
stepnumber1Amount added/removed per ArrowUp/ArrowDown press and per caret stepper click. Decimals work.
valuenumber | string—Controlled numeric value. Omit for uncontrolled (use `defaultValue`).
defaultValuenumber0Uncontrolled initial value. Use instead of `value`.
onChange(value: number) => void—Called with the next clamped number.
disabledboolean—Disabled - the input and both steppers go inert.
size'sm' | 'md' | 'lg'—Control height: sm - md (default) - lg.
classNamestring—Extra class(es) merged onto the field root.
styleCSSProperties—Inline styles merged onto the field root.
idstring—Field id, ties the label to the control.
labelReactNode—Label text (sentence case).
helperReactNode—Neutral helper text - shown when there's no validation message.
errorReactNode—Error message - sets the error state (border + icon + colour). Wins over warning/success/helper.

Frequently asked questions

Pass min (default 0) and max (default Infinity) - typing, the arrow keys and the caret steppers all clamp into that range, and the stepper buttons themselves disable once the value reaches either bound.

Pass unit as a string, e.g. <NumberField unit="users" /> - it renders inside the field, between the digits and the stepper column, without becoming part of the number onChange returns.

No - it renders <input type="text" inputMode="decimal"> with its own digit filter and caret steppers, which sidesteps the native number input's scroll-to-change behavior and inconsistent spin buttons, while inputMode="decimal" still raises the numeric keypad on mobile.

Pass step (default 1) - decimals work, so step={0.5} is valid - and it sets how much each arrow-key press or stepper click adds or removes. Typed values are still clamped to min/max but are not rounded to the step.

Set in Geist & Newsreader — animated by the house engineZyncat UI · Rev 0.11 · MIT · Built by Tabsir Ahammed · Source on GitHub