A text field for numbers, with increment and decrement buttons, keyboard stepping, and locale-aware formatting for decimals, currency, units and percentages.
import { NumberField } from "@rdloom/react";
export default function NumberFieldBasicExample() {
return (
<div className="w-48">
<NumberField label="Quantity" defaultValue={1} minValue={1} maxValue={99} description="Between 1 and 99." />
</div>
);
}Installation
npx rdloom add number-fieldCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/number-field.jsonWorks, but without upgrade tracking.
Usage
import { NumberField } from "@rdloom/react";
<div className="w-48">
<NumberField label="Quantity" defaultValue={1} minValue={1} maxValue={99} description="Between 1 and 99." />
</div>Currency
import { NumberField } from "@rdloom/react";
// formatOptions follows the visitor's locale for symbols and separators.
export default function NumberFieldCurrencyExample() {
return (
<div className="w-56">
<NumberField
label="Budget"
defaultValue={1500}
step={50}
minValue={0}
formatOptions={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }}
/>
</div>
);
}Stepper off
import { NumberField } from "@rdloom/react";
// Without the buttons it is a plain numeric field; the arrow keys still step it.
export default function NumberFieldStepperOffExample() {
return (
<div className="w-48">
<NumberField label="Age" showStepper={false} minValue={0} maxValue={130} isRequired />
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
labelrequiredVisible label, also the accessible name. | string | none |
descriptionHelp text under the field. | string | none |
errorMessageShown when the value is invalid. Leave out to use the browser's built-in message. | string | none |
valueControlled value. An empty field has no number. | number | none |
defaultValueInitial value when uncontrolled. | number | none |
onChangeCalled with the number, or with a value that is not a number when the field is emptied (test it with Number.isNaN). | (value: number) => void | none |
minValueSmallest allowed value. Typing below it is corrected on blur. | number | none |
maxValueLargest allowed value. | number | none |
stepHow much the buttons and the arrow keys change the value. Values snap to multiples of the step, counted from minValue (or from 0 when there is none). | number | 1 |
formatOptionsHow the number is shown and parsed, e.g. { style: 'currency', currency: 'USD' } or { style: 'percent' }. Follows the user's locale. | Intl.NumberFormatOptions | none |
showStepperShows the − and + buttons. Arrow keys and the mouse wheel stay available. | boolean | true |
sizeField height and text size. | "sm" | "md" | "lg" | "md" |
isDisabledPrevents interaction and dims the field. | boolean | false |
isInvalidMarks the field invalid. Leave it unset to let validation decide. | boolean | none |
isRequiredMarks the field required and adds an asterisk. | boolean | false |
Accessibility
Role spinbutton, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Up and Down arrows change the value by one step
- Page Up and Page Down change it by ten steps
- Home and End jump to the minimum and maximum, when set
- Typing a number is always possible; the buttons are a convenience
Screen readers announce
- Announced as a spin button with its label, current value, and the allowed range if set
- Changing the value with the arrow keys announces the new value
- An error is read with the field
What your code must do
- A labelled spinbutton exposing aria-valuenow, aria-valuemin and aria-valuemax when set
- The − and + buttons have accessible names and are not tab stops, so the keyboard doesn't get slower
- Invalid state and the error message are linked to the input
- Formatting follows the user's locale for decimal and grouping separators
Guidelines
Use it when
- Quantities, amounts, percentages and other numeric input people may type or nudge
- Values with a sensible range or step
Avoid it when
- Identifiers that merely look like numbers (phone, postcode, card number): use TextField
- Picking from a wide continuous range: use Slider
Don't
- Using it for phone numbers or IDs
- Hiding the unit instead of using formatOptions
- A min and max that make the typed value surprising with no error message
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-default--rd-color-surface-subtle--rd-color-border-default--rd-color-border-strong--rd-color-text-default--rd-color-text-muted--rd-color-feedback-danger--rd-color-focus-ring--rd-radius-control