InputNumber Atom

A text input that speaks numbers rather than <input type="number">, which scrolls its value away under the wheel, accepts e and +, and formats inconsistently across locales.

Usage

Between 1 and 10.

Steps of 0.25 — no floating point crumbs.

Current value: 3

tsx
<Field label="Seats" hint="Between 1 and 10.">  <InputNumber value={seats} onValueChange={setSeats} min={1} max={10} /></Field>

What it gets right

  • Clamping happens on blur, not on keystroke. Clamping while someone types fights them: type 1 toward 15 in a field with min={10} and the naive version rewrites it to 10 mid-word.
  • Steps do not leak floating point. 0.1 + 0.2 reads as 0.3, because the step's own precision decides the rounding.
  • An empty field is null, not 0. Those mean different things, and a form that confuses them saves zero when a person meant "unset".
  • A comma decimal separator parses. Half the world types 12,5.
  • The step buttons disable when they would do nothing — at max, the increase button is out.

Props

PropTypeDefaultNotes
value / defaultValuenumber | nullnull is the empty field, and it is a real value.
onValueChange(value: number | null) => voidFires while typing; the clamped value arrives on blur.
min / maxnumberBounds. Applied on blur and by the step buttons.
stepnumber1Also sets the rounding precision.
suffixstringUnit shown inside the control. Decorative — keep the unit in the label too.
size / disabled / invalidAs every other control.

Do

Give bounded fields a min and max, so the step buttons can tell a person where the edges are.

Don't

Use it for a phone number or a PIN — those are text that happens to be digits.