Number input

Takes a number and steps it.

Sizes

  • sm

  • defaultdefault

  • lg

Unit

  • nonedefault

  • unit

States

  • rest

  • focus

  • at a bound

  • invalid

  • disabled

  • read-only

Usage

When to use it
Use
A count or an amount the person nudges more than types: retries, a timeout, a token budget.
Use
A number with bounds the field should hold to (min, max).
Not for
A rough value on a scale where the exact number matters less. Use Slider.
Not for
An ID, a code or a phone number; digits are not a quantity. Use Input.
Not for
A one-time code. Use OTP input.

Rules

6 rules
Must
Pass the unit as unit, never in the label or as text beside the pill. Because unit sits inside the line and is read with the value ("30 s"); beside the pill it is outside the field and read separately.
Must
Set min and max when the value has limits. Because without them the steppers walk past the limit and the error arrives only on submit.
Must
Name it with a Field and FieldLabel, or aria-label. Because the steppers say Increase and Decrease, and nothing says what.
Never
Use it for an ID, a card number or a phone number. Because the steppers and the arrow keys change digits that are a name, not a quantity, and leading zeros are dropped.
Should
Set step to the change a person makes, and largeStep to ten of them.
Should
Pass format for currency or percent instead of a unit.

State order

5 states, highest first
1
disabled
2
invalid
3
focus
4
read-only
5
rest

Accessibility

4 checks
The text is a textbox with inputmode="decimal"; Base UI keeps the value clamped and announces the formatted number.
The steppers are named Increase and Decrease and stay out of the tab order; the arrow keys do their job from the text.
The unit is in the pill for the eye and read through the label or aria-describedby for a screen reader.
Focus darkens the line to --line-focus, as Input does.

Keyboard

3 keys
Up, Down
Step by step; with Shift by largeStep, with Alt by smallStep.
Home, End
Go to min and max, when set.
Enter
Submits the form around it.

Edge cases

5 edge cases
Typed out of range
Clamped to the bound on blur.
Typed text that is not a number
Reverts to the last number on blur.
Stepper held
Repeats until released or the bound, where it turns off.
Narrow field
The value shrinks before the steppers, which keep their size.
Right to left
The steppers swap ends; digits keep their order.

API

8 props
value, defaultValue, onValueChange
number | null
min, max
number
step, smallStep, largeStep
number default 1, 0.1, 10
unit
string
format, locale
Intl.NumberFormatOptions, string
size
'sm' | 'default' | 'lg' default 'default'
leading
ReactNode
aria-invalid
boolean

Tokens

19 tokens
--paper
#ffffff
--field
#efefef
--line-control
rgb(5 5 5 / 0.15)
--line-focus
rgb(5 5 5 / 0.32)
--line-faint
rgb(5 5 5 / 0.06)
--fail
#e35e49
--hover
rgb(5 5 5 / 0.06)
--pressed
rgb(5 5 5 / 0.10)
--text-1
rgb(5 5 5 / 0.80)
--text-3
rgb(5 5 5 / 0.45)
--text-disabled
rgb(5 5 5 / 0.32)
--control-sm
26px
--control
32px
--control-lg
36px
--shell-inset
3px
--radius-pill
999px
--type-body-sm
400 13px/1.5 var(--font-sans)
--type-caption
400 12px/1.35 var(--font-sans)
--type-body
400 14px/1.5 var(--font-sans)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.