Skip to content

Number Field

A text field for numbers, with increment and decrement buttons, keyboard stepping, and locale-aware formatting for decimals, currency, units and percentages.

Inputv0.1.0experimentalWCAG 2.2 AAView spec
Between 1 and 99.
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-field

Copies 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.json

Works, 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.

PropTypeDefault
labelrequired

Visible label, also the accessible name.

stringnone
description

Help text under the field.

stringnone
errorMessage

Shown when the value is invalid. Leave out to use the browser's built-in message.

stringnone
value

Controlled value. An empty field has no number.

numbernone
defaultValue

Initial value when uncontrolled.

numbernone
onChange

Called with the number, or with a value that is not a number when the field is emptied (test it with Number.isNaN).

(value: number) => voidnone
minValue

Smallest allowed value. Typing below it is corrected on blur.

numbernone
maxValue

Largest allowed value.

numbernone
step

How 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).

number1
formatOptions

How the number is shown and parsed, e.g. { style: 'currency', currency: 'USD' } or { style: 'percent' }. Follows the user's locale.

Intl.NumberFormatOptionsnone
showStepper

Shows the − and + buttons. Arrow keys and the mouse wheel stay available.

booleantrue
size

Field height and text size.

"sm" | "md" | "lg""md"
isDisabled

Prevents interaction and dims the field.

booleanfalse
isInvalid

Marks the field invalid. Leave it unset to let validation decide.

booleannone
isRequired

Marks the field required and adds an asterisk.

booleanfalse

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