Library / SDK
catamphetamine/react-phone-number-input avatar
catamphetamine/react-phone-number-input

react-phone-number-input: an E.164 phone input for React

React component for international phone number input

976 stars196 forksJavaScriptMIT

At a glance

What is it?
react-phone-number-input ships two components, one with a country select and flags and one deliberately bare, and the value it gives you is always a parsed international number in E.164 format rather than whatever string the user typed. The packaging is the other story, with a dozen entry points for different feature levels.
Who is it for?
react-phone-number-input suits a React application that needs a phone number the user can enter in their own local format and that must store it in a single unambiguous international form, and its E.164 contract is the reason to pick it over a plain input with a country dropdown. It is a poor fit if you need to accept numbers that are not phone numbers, such as extensions or short codes, since the parsing library is the constraint.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 147 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Two components, and the choice is about styling

The package exports two variants of the input component, and the readme frames the decision in terms of what you prefer rather than what you need.

The first is the component with a country select, a phone number input field with a country select on the left side. The readme calls this the most straightforward and easy to use one, and it is the one that gives you everything out of the box: the CSS styles, the country flags, and the country labels in different languages.

The second is the component without a country select, which is just the phone number input field. The readme describes it as the bare-bones variant, for people who like minimalism or who would like to build their own.

That framing matters more than it appears. A component library that gives you styles, flags and translated country names is making a set of decisions for you, and some applications cannot accept those decisions because they have a design system, because their users are in one country, or because they want the country choice somewhere other than next to the field. The bare variant is the escape from all of that.

The flag images and the country label translations are in separate top level directories in the repository, alongside the input implementation directories and a locale directory, so the pieces are separable in the source as well as in the package.

The country select itself is rendered as a native select element, with the desktop and mobile screenshots in the documentation showing the platform's own picker rather than a custom dropdown, which is the right call for a control that has to work with a screen reader and with a phone's native behaviour.

The value contract is E.164, and it is the whole point

The two required properties are the value and the change handler, and the semantics of both are worth reading closely.

When the user types something, the change handler is called with the parsed phone number in E.164 format. The readme gives the example: if the user chooses United States and enters the number in a national format with parentheses and dashes, the handler is called with the string in the plus and digits form. That means your application never sees the raw keystrokes and never has to strip punctuation, which is the single most common source of corrupted phone numbers in a database.

When the user clears the field, the handler is called with undefined. The readme notes that null might have been better, but that historically it was decided to be undefined. That is the kind of detail that saves a bug report later, because a form that treats undefined and null differently will misbehave with one of them.

The value property takes the same format, and any falsy value, whether undefined, null or the empty string, is treated as no value. So the component does not distinguish between an empty field and an unset one, which is convenient and also means you cannot represent an empty string as a legitimate value.

The optional properties are the initially selected country, which must be a two letter country code, and a change handler for the country, called with the new country code. Anything else, such as a placeholder, is passed through to the underlying input element, so the component is not a closed API that hides the input from you.

The export map is a dozen ways to install the same idea

The package manifest is the most surprising document in the repository, and it explains the size of the top level directory listing.

The package version is 3.4.17, the module field is marked as an ES module, and there is a type declaration file at the root. But the real content is the exports map, which offers the main entry point and then a dozen more.

There is an entry for the full component, one for the minimal build, one for a mobile build and one for a core build. There is a separate entry for the flags images on their own, and then a parallel set of entries for the input component alone, in core, minimal, max and mobile variants. And there is an entry for the react-hook-form integration.

That is a lot of surface area, and the reason for it is a packaging problem rather than an API design problem. If you import the main entry you get the flags and the country labels whether you use them or not, and in a project that cares about bundle size that is a real cost. The core entry gives you the parsing and formatting without any of that.

The react-hook-form entry is the other telling one, and the directory listing shows the integration is built on top of the input components rather than being a separate implementation, with a core directory and an input directory for it. Since the component is a controlled one with a value and a change handler, wiring it into a form library is the natural thing to want.

The type declarations are exported alongside each entry point rather than once at the root, which means TypeScript resolution works for every variant.

Stylesheets, custom properties and the ancient browser caveat

The component with the country select requires its stylesheet, and the documentation is specific about how that should be done and how it should be themed.

All the CSS class names start with a prefix, so they do not conflict with the application's own styles, and there are status modifier classes for the focus, disabled and read-only states.

The stylesheet uses native CSS custom properties, and the readme names the ones of interest, such as the height of the flag icon and its border colour. That is the theming mechanism, and it is the modern one: change a variable and the flag changes.

The caveat is stated in the same paragraph. Native CSS variables have been supported in all modern browsers for a long time, but ancient ones like Internet Explorer do not support them. If compatibility with such ancient browsers is required, the readme suggests using a CSS transformer like PostCSS with a plugin for custom properties.

That recommendation is the tell that this library is maintained for a long time rather than designed fresh. A component written today would simply require CSS variables and drop the old browsers. A component that has been in use for years has to keep working for the applications that have not been redesigned, and it does so by documenting the escape hatch rather than by dropping support.

The colour of the flag and its size are set through variables rather than through a prop, which is a constraint worth knowing: if your application needs a different flag treatment per instance, you are overriding custom properties rather than passing props.

The parsing library and a Samsung Android issue

Two comments in the readme, both marked as hidden in the rendered page, carry the most useful technical information in the file.

The first is that the input is based on libphonenumber-js, the phone number parsing and formatting library, which is where the E.164 contract comes from. That library is maintained by the same author, and it is the component that decides what counts as a valid number, which country a national format belongs to and how to render it back for display.

The second is about the input element itself. The phone number input is implemented using a separate library called input-format, and the readme notes that it has an issue with some Samsung Android phones, with a link to a workaround section in the documentation.

That is a small, concrete and useful disclosure. Input masking on Android, particularly on Samsung's modified keyboard and its custom input method, is a well known source of trouble, and the usual symptom is that the caret jumps or the mask fights the user. A library that tells you the workaround exists, and where to find it, is doing you a favour that a big dependency rarely bothers with.

It is also a reason to test the component on real devices rather than in a desktop browser emulator, which is advice that applies to any component that manipulates the value of a native input.

Version 3, a changelog, and where the project lives

The readme states which version it documents and what happened to the previous one.

This is a readme for the latest version, the 3.x line, and the previous 2.x readme could be found on GitHub until it was removed, with a pointer to the changelog for migrating from 2.x to 3.x. So the 3.x line is a deliberate break, and the changelog is the document that explains what broke.

That is the pattern of a library that has been through a major redesign, which fits the packaging evidence. A dozen entry points with a core build that has no styles, a separate flags entry, a mobile entry and a form library integration is not the shape of version 2 of a small component.

The package is installed with npm:

bash
npm install react-phone-number-input --save

Alternatively it can be included on a web page directly through a script tag.

The licence is MIT, the project is not archived, and the last push was on 2026-05-29. There are no GitHub releases, so the version to install comes from the npm registry, where the package carries download and version badges.

The hosting is a little unusual. The readme's links point at GitLab for the project pages, the changelog and the source of the input-format library, and the project pages and the demo are on the GitLab pages domain, while the repository itself is on GitHub. A migration of the source of truth, or a split between the two, would explain that, and it is worth checking which one is authoritative before you file an issue or a pull request.

The repository also carries a code of conduct, a changelog, a styleguidist configuration for the documentation site, a Rollup build configuration, a Babel configuration and a test directory, so the build and the interactive documentation are both part of the tree rather than being external tooling.

Editorial conclusion

react-phone-number-input suits a React application that needs a phone number the user can enter in their own local format and that must store it in a single unambiguous international form, and its E.164 contract is the reason to pick it over a plain input with a country dropdown. It is a poor fit if you need to accept numbers that are not phone numbers, such as extensions or short codes, since the parsing library is the constraint. Before you adopt it, decide which of the entry points you want, because the package exposes separate builds for a full feature set, a minimal one, a mobile one and a core one with no styles, and check the documented workaround for the input implementation on some Samsung Android phones.

Frequently asked questions

How do I install react-phone-number-input?

With npm install react-phone-number-input --save, or by including it on a page directly through a script tag. The package publishes to npm at version 3.4.17 with type declarations and separate entry points for the full, minimal, mobile and core builds.

What format is the phone number in when onChange fires?

It is the parsed number in E.164 format, for example the number entered as (213) 373-4253 for the United States arrives as the string with the country code and digits only. When the field is cleared, the handler is called with undefined, which the readme notes was a historical decision rather than a preference.

What is the difference between the two components react-phone-number-input exports?

The variant with a country select provides styles, country flags and country labels in different languages out of the box, and needs its stylesheet included. The variant without a country select is the bare-bones input field, for people who want minimalism or who want to build the surrounding interface themselves.

Does react-phone-number-input work on Android phones?

There is a known issue: the input element is implemented using the input-format library, which has an issue with some Samsung Android phones, and the readme links to a documented workaround. The parsing and formatting come from libphonenumber-js.

Official sources

  1. catamphetamine/react-phone-number-input on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/catamphetamine-react-phone-number-input.svg)](https://hysenlabs.com/projects/catamphetamine-react-phone-number-input)

Was this useful?