Number Input
Enter or step through a number, formatted for your locale, currency or unit.
import { NumberInput } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a number input when the answer is a quantity people adjust: a budget, a replica count, a timeout, a discount. It parses what they type in the locale it formats in, clamps it to min and max, and formats it back with Intl.NumberFormat. For a value picked along a range by feel, use a Slider. For digits that aren't a quantity, such as a verification code or a phone number, use Input OTP or Phone Input.
import { useState } from 'react'
import { Field, FieldLabel, NumberInput } from '@youj/react'
export function Replicas() {
const [replicas, setReplicas] = useState<number | null>(3)
return (
<Field>
<FieldLabel>Replicas</FieldLabel>
<NumberInput value={replicas} onValueChange={setReplicas} min={1} max={20} />
</Field>
)
}The value is a number, or null when the field is empty. It's built on Base UI's NumberField and rendered as an Input Group, so it takes a Field's label, description, error and required with no extra wiring.
Description
A monthly budget formatted as US dollars, stepping by 100, or by 1,000 with Shift.
Arrow keys and the buttons move by step. Shift with an arrow moves by largeStep, which defaults to 10. Pressing and holding a button repeats, and Home and End jump to min and max. The mouse wheel doesn't change the value unless you set allowWheelScrub, because a page scrolling past a focused field shouldn't edit a form.
Currency, percent and unit formats.
format takes Intl.NumberFormat options, so currency, percent and units come from the platform: the symbol, the separators and the placement all follow the locale. A percent value is a fraction, so 0.15 shows as 15%. unit and prefix add a plain text addon instead, for units Intl doesn't know, like req/min.
Invalid and disabled fields, a locale and the steppers option.
Inside an invalid Field the group takes the error treatment, and a disabled Field disables the input and both buttons. locale sets the parsing and display locale (default: the YoujProvider's locale, en-US without one), and steppers={false} drops the buttons for a plain formatted field.
Code
number-input-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsvalue, defaultValue, onValueChange… (23)
Props
| Prop | Type | |
|---|---|---|
value | number | null | – |
defaultValue | number | null | – |
onValueChange | (value: number | null) => void | – |
min | number | – |
max | number | – |
step | numberPer ArrowUp/Down and button press. default 1 | 1 |
largeStep | numberPer Shift+ArrowUp/Down. default 10 | 10 |
format | Intl.NumberFormatOptionsIntl.NumberFormat options: { style: 'currency', currency: 'USD' }, { style: 'percent' }, { style: 'unit', unit: 'gigabyte' }… | – |
locale | Intl.LocalesArgumentDefault: the YoujProvider locale. | – |
unit | ReactNodeA plain suffix addon ("GB", "req/s"). | – |
prefix | ReactNodeA plain prefix addon. | – |
allowWheelScrub | booleanLet the mouse wheel step the value while the field is focused. default false | false |
steppers | booleanShows the − / + buttons. default true | true |
placeholder | string | – |
disabled | boolean | – |
readOnly | boolean | – |
required | boolean | – |
name | string | – |
id | string | – |
ref | Ref<HTMLInputElement> | – |
onBlur | () => void | – |
className | string | – |
aria-label | string | – |
MotionStep, stepper press · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Stepthe number nudges 3px from the direction it moved: up for more, down for less | duration.fastease.enter140ms · cubic-bezier(0.16, 1, 0.3, 1) | 140mscubic-bezier(0.16, 1, 0.3, 1) | |
| Stepper pressthe − and + buttons press like every Button | duration.instantease.standard80ms · cubic-bezier(0.2, 0, 0, 1) | 80mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
The number changes in place with no nudge.
A held button fires a step on every repeat, and each one restarts the nudge, so a fast count reads as movement rather than a flicker. Typing a value never nudges: only steps from the keyboard, the buttons or the wheel do.
Reduced motion
Steps change the number in place, with no nudge. Formatting, clamping and press-and-hold are unchanged.
AccessibilityKeyboard, ARIA, announcements
Accessibility
- It's Base UI's NumberField: a text input described as a number field, inside a group, so screen readers hear the formatted value as it changes.
- ArrowUp and ArrowDown step by
step, Shift with an arrow bylargeStep, and Home and End go to the bounds. - The steppers are named "Decrease" and "Increase". They stay out of the tab order, because the arrow keys already do their job from the input.
- Name it with a Field's label, or with
aria-labelon its own. Aunitaddon is visible text, so the label doesn't need to repeat it.