mrkeyoor.com_
Sat 08 Aug 20:59 UTC
npmWeb Frontendupdated 08 Aug 2026

react-number-format

react-number-format is a React input formatter with a caret engine that keeps editing usable while separators, prefixes, suffixes, decimal rules, or fixed digit patterns are applied. Version 5 splits the public UI into `NumericFormat` for quantities and currency-like input, `PatternFormat` for phone, card, and identifier shapes, and `NumberFormatBase` plus hooks for custom rules. It can also render formatted text, includes TypeScript declarations, and has no runtime dependencies. It formats and constrains keystrokes; it does not validate a currency, phone number, card number, or business rule by itself.

Verdict

One of the better React choices when caret-correct numeric editing is the hard part, especially with controlled numeric-string state. Skip it for display-only formatting or semantic validation, and read the v5 value-shape and event rules before wiring it into forms.

API stability4/5Version 5 has a clear division between NumericFormat, PatternFormat, and NumberFormatBase, and the value object, source information, formatting utilities, and hooks are all documented and typed. The public surface has been stable across the 5.4 line. The v4 to v5 migration was substantial: the default component split into named exports, `isNumericString` was renamed, custom function formatting moved, and customNumerals was removed, so future major upgrades deserve real input and caret regression tests.
Docs5/5The documentation has separate prop references for numeric and pattern formats, live demos, a v4 migration guide, customization concepts, hooks and utility APIs, and an unusually valuable quirks page. That page explicitly explains the three value forms, exponential float risk, `valueIsNumericString`, sourceInfo, event differences, mobile input types, decimal blocking, and why native length props fail. A few prose examples are dated stylistically, but the current-version behavior is unusually well exposed.
Maintenance4/5Version 5.4.5 was published on March 22, 2026 and the repository was pushed the same day. It is not archived, supports React 19, ships declarations, and maintains a browser test suite focused on the difficult caret and input behavior. GitHub reports 229 open issues and pull requests, a sizable queue that reflects both broad use and the large browser, input-method, mobile, form-library, and custom-component compatibility surface a small project must support.
Ecosystem5/5The npm last-week endpoint recorded 4,719,974 downloads and the repository has 4,101 stars. It declares peers across React 0.14 through 19, has no runtime dependencies, includes types, passes ordinary input props through, and documents custom components such as Material UI TextField. The focused API works with form libraries through controlled values, but it does not provide built-in locale data, schema validation, or framework-neutral use, so those integrations remain application work.

Use it if

  • You need thousands separators, decimal limits, prefixes, suffixes, and stable caret behavior while a React user types
  • You need fixed digit patterns such as phone or card layouts with placeholders and mobile-keyboard hints
  • You want formatted display and editable input to share the same rules and value object
  • You have unusual formatting rules and can build them on NumberFormatBase, useNumericFormat, or usePatternFormat
Skip it if

Setup reality

Install with `npm install react-number-format`; there are no runtime dependencies, stylesheet imports, native extensions, credentials, or config files. React and ReactDOM are peers, with version 5.4.5 declaring compatibility from React 0.14 through 19, and TypeScript declarations ship in `types/index.d.ts`. The first migration trap is old examples: version 5 removed the default `NumberFormat` component in favor of named `NumericFormat` and `PatternFormat` exports, renamed `isNumericString` to `valueIsNumericString`, and moved custom format functions to `NumberFormatBase`. The second trap is state shape. `onValueChange` returns `formattedValue`, an unformatted numeric-string `value`, and `floatValue`; choose one representation and feed the same kind back. For currency and identifiers, the numeric string is usually safest. When a controlled value is an unformatted string and the format contains digits, or NumericFormat uses `.` as the thousands separator, set `valueIsNumericString` so the library does not interpret value digits as formatting. `onValueChange` is not a native change handler and can run because a prop changed or because blur reformatted the value; inspect its second argument's `source` before treating every call as user input. Native `onChange`, `onBlur`, and `onFocus` still receive normal input events and do not receive the value object. NumericFormat does not infer the user's locale. You must choose decimalSeparator, thousandSeparator, grouping style, allowed alternative separators, decimal scale, and negative-number policy. `decimalScale` rounds a controlled value, and `fixedDecimalScale` pads trailing zeros. PatternFormat's `#` slots accept digits but do not prove that the completed string is a real card number or reachable phone number. On mobile, the docs recommend `type="tel"` for fixed patterns, but `type="text"` for decimal input so users can type the decimal separator. `customInput` takes a component reference, not an inline render function; that component must forward the value, events, and ref expected by the formatter. `isAllowed` rejects an edit before value change and is the documented replacement for length props, but it should be fast and should allow intermediate states such as an empty field or a lone minus sign when those are part of editing. Display mode renders a span by default and `renderText` replaces it. Accessibility remains your job: provide labels, descriptions, error text, and semantic validation, and do not assume visual masking explains required input to a screen-reader user.

Patterns

Build a controlled currency-style inputformat-currency-input

import { NumericFormat } from 'react-number-format';

<NumericFormat
  value={amount}
  valueIsNumericString
  onValueChange={({ value }) => setAmount(value)}
  thousandSeparator=","
  decimalSeparator="."
  decimalScale={2}
  fixedDecimalScale
  prefix="$"
/>

Store the unformatted string for exact decimal digits. A prefix formats the field but does not identify or convert a currency.

Choose the correct value representationread-value-object

<NumericFormat
  onValueChange={({ formattedValue, value, floatValue }, sourceInfo) => {
    console.log({ formattedValue, value, floatValue, source: sourceInfo.source });
  }}
/>

`floatValue` can lose precision or use exponential notation; `value` is the safer state form for money and long identifiers.

Use comma decimals and dot groupingaccept-european-separators

<NumericFormat
  value={amount}
  valueIsNumericString
  thousandSeparator="."
  decimalSeparator=","
  allowedDecimalSeparators={[',', '.']}
  onValueChange={({ value }) => setAmount(value)}
/>

`valueIsNumericString` is required here because the unformatted string is paired with `.` as the thousands separator.

Reject values outside a business limitlimit-value-range

<NumericFormat
  value={quantity}
  onValueChange={({ value }) => setQuantity(value)}
  decimalScale={0}
  allowNegative={false}
  isAllowed={({ floatValue }) => floatValue == null || floatValue <= 1000}
/>

Allow `floatValue == null` so the user can clear the field; isAllowed returning false blocks the edit and value callback.

Format a fixed phone-number patternformat-phone-pattern

import { PatternFormat } from 'react-number-format';

<PatternFormat
  format="+1 (###) ###-####"
  mask="_"
  type="tel"
  value={phoneDigits}
  valueIsNumericString
  onValueChange={({ value }) => setPhoneDigits(value)}
/>

This restricts and formats digits but does not validate whether the number exists or whether its area code is valid.

Format card-number digitsmask-card-number

<PatternFormat
  format="#### #### #### ####"
  mask="_"
  type="tel"
  value={cardDigits}
  valueIsNumericString
  onValueChange={({ value }) => setCardDigits(value)}
/>

The pattern neither runs a Luhn check nor handles every card length. Keep full card data out of ordinary application state and logs.

Render a noneditable formatted numberrender-formatted-text

<NumericFormat
  value="1234567.5"
  valueIsNumericString
  displayType="text"
  thousandSeparator
  prefix="$"
  decimalScale={2}
  fixedDecimalScale
/>

For display-only locale-aware currency, native Intl.NumberFormat is often a smaller and more semantic choice.

Format a design-system inputuse-custom-input

import { TextField } from '@mui/material';

<NumericFormat
  customInput={TextField}
  label="Budget"
  value={budget}
  valueIsNumericString
  thousandSeparator
  onValueChange={({ value }) => setBudget(value)}
/>

Pass a component reference, not `customInput={() => <TextField />}`; the docs say an inline render component will not work.

Get the underlying input referencefocus-input-ref

const inputRef = useRef<HTMLInputElement | null>(null);

<NumericFormat
  getInputRef={(element) => { inputRef.current = element; }}
  thousandSeparator
/>

// later
inputRef.current?.focus();

With a customInput, the referenced instance depends on that component's ref forwarding rather than always being a native input.

Ignore value callbacks caused by prop updatesdistinguish-user-changes

<NumericFormat
  value={amount}
  valueIsNumericString
  onValueChange={({ value }, { source }) => {
    if (source === 'event') setAmount(value);
  }}
/>

onValueChange can run for user events or prop changes, and it may run on blur; it is not equivalent to the native onChange event.

Reuse numeric formatting outside JSXformat-without-component

import { numericFormatter } from 'react-number-format';

const label = numericFormatter('1234567.5', {
  thousandSeparator: ',',
  decimalScale: 2,
  fixedDecimalScale: true,
  prefix: '$',
});

The first argument is an unformatted numeric string. For ordinary locale display, compare this with Intl.NumberFormat.

Accept whole numbers onlyblock-decimal-input

<NumericFormat
  value={count}
  valueIsNumericString
  decimalScale={0}
  allowNegative={false}
  onValueChange={({ value }) => setCount(value)}
/>

The quirks guide recommends `decimalScale={0}` to block floating-point input; native maxLength is not a reliable formatted-value constraint.

Alternatives

PackageRegistryPick it when
react-currency-input-fieldnpmChoose it when the requirement is specifically a React currency and numeric field with a narrower API
react-imasknpmChoose it for broader masks, typed values, dates, and mixed character patterns beyond numeric placeholders
cleave.jsnpmChoose it when the formatter must also serve non-React pages or several frontend frameworks