Skip to content

NumberField

NumberField is a text input field tailored to numbers.
Figma logo
  • NumberField is a field element that wraps NumberInput with label, helper, and validation text.
  • NumberField will format its value on blur using the information provided to the locales and options props.
  • NumberField should not be used for zip codes; use TextField instead.
  • This example implements a required NumberField formatted for currency.
  • NumberInput will automatically prepend the appropriate currency symbol using the before or after prop.
  • The input will be validated and formatted on blur.
  • This example leverages native props to validate the input. It will require an integer value greater than or equal to 18 and less than or equal to 150.
  • The step={1} prop indicates that the value should be an integer.
  • inputMode="numeric" adapts mobile keyboards to numerical inputs.
  • The minimumFractionDigits and maximumFractionDigits options can be used to allow fractions to be displayed within the input.
  • NumberInput will add the percent symbol using the after prop when using style: 'percent'.
  • The output value will be on a scale of zero to one. For example 2.35% will output 0.0235.
  • Different locales use different groupings of numbers, different characters for groups and decimals, and potentially even different number systems.
  • Use the locales prop to format within another locale.
  • NumberField will occupy the width of its parent by default.
  • The size and fit props can be used to fit the size to its content.

Disabled states should be used with caution.

It may sometimes be necessary to hide labels, but label text must still be made available for screen readers. This example uses visuallyHidden to visually hide the label.

React props
NameTypeDefaultDescription
after  ReactNodeContent shown after the input value.
before  ReactNodeContent shown before the input value.
component  ReactNodeComponent override for the input element.
counter  ReactNodeIndicator of a limit placed on a field, e.g. maximum character count or remaining hours.
fit  contentcontainercontainerDetermines the point of reference for the width of the component. If set to content, the size will be set by the size attribute of the input. If set to container, the size will expand to fit the containing element.
helperText  ReactNodeAdditional descriptive information for the input.
inputMode  decimalnumericdecimalDetermines the keyboard on mobile devices. A decimal keyboard will be able to enter a decimal point. For integer input, use inputMode="numeric".
invalid  booleanfalseIf true, the input will be shown in an invalid state.
label  RequiredReactNodeLabel for the associated input.
locales  stringstring[]Locale code forwarded to Intl.NumberFormat
E.g. "en", "en-US", or "fr-FR".
name  RequiredstringName of the input. Submitted with the form as part of a name/value pair.
optionalText  stringText used to indicate that a field is not required.
options  objectOptions forwarded to Intl.NumberFormat
E.g. { style: 'currency', currency: 'USD' }
size  numberUsed in conjunction with the fit prop to specify the width of the input.
validationText  ReactNodeValidation message associated with the input.

The following testing snippet(s) offer suggestions for testing the component using React Testing Library with occasional help from Jest.

// BASIC TESTS
render(
<NumberField
label="Label"
helperText="Helper text"
options={{
style: 'currency',
currency: 'USD',
}}
/>,
);
const input = screen.getByLabelText('Label');
expect(input).toHaveAccessibleDescription('Helper text');
userEvent.type(input, '12345.6');
expect(input).toHaveDisplayValue('12345.6');
// Input is not formatted until the field is blurred
userEvent.tab();
expect(input).toHaveDisplayValue('12,345.60');
const inputContainer = input.parentElement as HTMLDivElement;
expect(inputContainer).toHaveTextContent('$');
// TESTING VALIDITY
render(<NumberField label="Label" invalid validationText="Validation text" />);
const input = screen.getByLabelText('Label');
expect(input).toBeInvalid(); // or expect(input).not.toBeValid();
expect(input).toHaveAccessibleDescription('Validation text');
// TESTING MULTIPLE DESCRIPTIVE ELEMENTS
render(
<NumberField
label="Label"
optionalText="(optional)"
helperText="Helper text"
validationText="Validation text"
/>,
);
const input = screen.getByLabelText('Label');
expect(input).toHaveAccessibleDescription(expect.stringContaining('(optional)'));
expect(input).toHaveAccessibleDescription(expect.stringContaining('Helper text'));
expect(input).toHaveAccessibleDescription(expect.stringContaining('Validation text'));
// or all at once:
expect(input).toHaveAccessibleDescription('(optional) Helper text Validation text');
// TESTING BEFORE AND AFTER
render(<NumberField label="Label" before="Before" after="After" />);
const inputContainer = screen.getByLabelText('Label').parentElement as HTMLDivElement;
expect(container).toHaveTextContent('Before');
expect(container).toHaveTextContent('After');