npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-phone-field

v0.1.0

Published

International phone number input for React Native with country code picker, search, libphonenumber formatting, Gorhom bottom sheet, headless mode, and localized country names. Expo & TypeScript ready.

Readme

react-native-phone-field

npm version npm downloads license TypeScript

The international phone number input for React Native — country code picker, live formatting, validation, and a searchable country list. Works with Expo and bare React Native on iOS and Android.

Drop-in PhoneInput with a Gorhom bottom sheet, or go headless and plug in your own modal, TrueSheet, or native sheet. Fully typed, themeable, RTL-ready, and localized country names out of the box.

npm install react-native-phone-field @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-transformer-text-input react-native-worklets
import { PhoneInput } from 'react-native-phone-field';

<PhoneInput
  value={phone}
  onChangePhoneNumber={setPhone}
  selectedCountry={country}
  onChangeSelectedCountry={setCountry}
  defaultCountry="FR"
  countryNameLocale="fr"
/>

Table of contents


Why use this library?

Building a phone field in React Native usually means wiring together a country picker, calling codes, libphonenumber-js, input masking, keyboard handling, and a bottom sheet. react-native-phone-field ships all of that in one package.

| You need… | This library gives you… | |-----------|-------------------------| | International phone input with country flag | PhoneInput with flag, dial code, and masked national number | | Searchable country list / country code picker | Built-in sheet with search, 240+ countries | | Phone number validation & formatting | libphonenumber-js + live masking via react-native-transformer-text-input | | Custom bottom sheet (Gorhom, TrueSheet, Modal) | Headless mode + reusable CountrySelectorContent | | Multi-language country names | 25 built-in locales + registerCountryNameLocale() | | Full UI control | Granular styles, render props, light/dark theme, RTL |

Ideal for sign-up flows, OTP / SMS verification, checkout forms, profile settings, and any screen that collects a mobile number.


Features

  • International phone number input — flag, calling code (+33, +1…), and formatted national number
  • Country picker with search — filter by country name, ISO code, or dial code
  • Gorhom bottom sheet included — production-ready picker via @gorhom/bottom-sheet
  • Headless architecture — use react-native-phone-field/headless with your own sheet (no Gorhom required)
  • Live input masking — national format as you type (react-native-transformer-text-input)
  • Validation helpersisValidPhoneNumber, formatPhoneNumber, getCountryByPhoneNumber
  • Localized country namescountryNameLocale prop + 25 built-in languages via i18n-iso-countries
  • Light / dark theme, RTL, error state, disabled state
  • Fully customizable — colors, layout styles, custom flag/caret/picker renders, sheet backdrop & icons
  • TypeScript — strict types for countries, props, and headless adapters
  • Expo compatible — example app included

Quick start

1. Install

npm install react-native-phone-field @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-transformer-text-input react-native-worklets
yarn add react-native-phone-field @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-transformer-text-input react-native-worklets

countries-list, libphonenumber-js, and i18n-iso-countries are bundled — no extra install.
Follow the Reanimated and Gesture Handler setup guides if needed.

2. Wrap your app

PhoneInput uses a Gorhom bottom sheet by default. Wrap your app with GorhomPhoneFieldProvider:

import { GorhomPhoneFieldProvider } from 'react-native-phone-field';
import { SafeAreaProvider } from 'react-native-safe-area-context';

export default function App() {
  return (
    <SafeAreaProvider>
      <GorhomPhoneFieldProvider>
        {/* your screens */}
      </GorhomPhoneFieldProvider>
    </SafeAreaProvider>
  );
}

Place GorhomPhoneFieldProvider outside any SafeAreaView so the sheet backdrop covers the full screen.

3. Add the phone input

import { useState } from 'react';
import { PhoneInput } from 'react-native-phone-field';
import type { ICountry } from 'react-native-phone-field';

function SignUpScreen() {
  const [phone, setPhone] = useState('');
  const [country, setCountry] = useState<ICountry | null>(null);

  return (
    <PhoneInput
      value={phone}
      onChangePhoneNumber={setPhone}
      selectedCountry={country}
      onChangeSelectedCountry={setCountry}
      defaultCountry="FR"
      countryNameLocale="fr"
      placeholder="6 12 34 56 78"
    />
  );
}

Tap the flag to open the country picker. Done.


Package exports

┌─────────────────────────────────────────────────────────┐
│  PhoneInput (default import)                            │
│  ├── PhoneInputCore        input, formatting, flag UI   │
│  └── useGorhomCountrySelector   bottom sheet picker     │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  PhoneInput from /headless                              │
│  └── PhoneInputCore + your own countrySelector          │
└─────────────────────────────────────────────────────────┘

| Import | Use when | |--------|----------| | react-native-phone-field | Default — Gorhom sheet included, fastest setup | | react-native-phone-field/headless | Your own sheet / modal — no Gorhom install | | react-native-phone-field/country-selector | Reuse the searchable country list in any sheet | | react-native-phone-field/sheets/gorhom | Gorhom adapter (useGorhomCountrySelector) directly |


Controlled state

PhoneInput is fully controlled. You own two pieces of state:

| State | Type | Description | |-------|------|-------------| | phone | string | National number (without calling code), formatted as you type | | country | ICountry \| null | Selected country (cca2, flag, callingCode, name) |

const [phone, setPhone] = useState('');
const [country, setCountry] = useState<ICountry | null>(null);

<PhoneInput
  value={phone}
  onChangePhoneNumber={setPhone}
  selectedCountry={country}
  onChangeSelectedCountry={setCountry}
/>

ICountry

interface ICountry {
  cca2: string;        // "FR", "US" …
  flag: string;        // "🇫🇷"
  callingCode: string; // "+33"
  name: string;        // "France" (English canonical name)
}

defaultCountry

Set the initial country on first mount (ISO 3166-1 alpha-2):

<PhoneInput defaultCountry="FR" ... />

Type-safe with DefaultCountry (alias of libphonenumber-js CountryCode):

import type { DefaultCountry } from 'react-native-phone-field';

const initial: DefaultCountry = 'FR';

If omitted, defaults to US.


Country name localization

Translate country names in the picker with a single prop:

<PhoneInput countryNameLocale="fr" defaultCountry="FR" ... />

25 built-in locales (zero config):
en, fr, de, es, it, pt, nl, ar, zh, ja, ko, ru, pl, tr, hi, he, sv, da, fi, cs, uk, vi, th, id

For any other language supported by i18n-iso-countries:

import { registerCountryNameLocale, BUILT_IN_COUNTRY_NAME_LOCALES } from 'react-native-phone-field';
import ro from 'i18n-iso-countries/langs/ro.json';

registerCountryNameLocale('ro', ro);

<PhoneInput countryNameLocale="ro" ... />

Headless / custom sheet:

import { CountrySelectorContent } from 'react-native-phone-field/country-selector';

<CountrySelectorContent locale="de" title="Land wählen" searchPlaceholder="Suchen…" ... />
import { useGorhomCountrySelector } from 'react-native-phone-field/sheets/gorhom';

useGorhomCountrySelector({ locale: 'de', title: 'Land wählen' });

UI strings (title, searchPlaceholder, notFoundMessage) are passed as props — wire them to your own i18n library (react-i18next, expo-localization, etc.).


Theming & styling

Light / dark

<PhoneInput theme="dark" ... />

Input colors

<PhoneInput
  colors={{
    text: '#ffffff',
    placeholder: '#888888',
    border: '#333333',
    borderFocused: '#0A84FF',
    borderError: '#FF453A',
    caretColor: '#0A84FF',
  }}
/>

Layout & shadow

<PhoneInput
  borderRadius={16}
  borderWidth={2}
  height={52}
  shadow={{
    color: '#000',
    offset: { width: 0, height: 2 },
    opacity: 0.1,
    radius: 4,
    elevation: 3,
  }}
/>

Granular styles

<PhoneInput
  phoneInputStyles={{
    container: { borderColor: '#e94560' },
    callingCode: { color: '#e94560', fontWeight: '700' },
    input: { fontSize: 18 },
    errorText: { marginTop: 8 },
  }}
/>

Country picker (sheet) styling

Colors (selectorColors):

selectorColors={{
  primary: '#e94560',
  text: '#000000',
  textSecondary: '#999999',
  selectedBackground: '#f0f0f0',
  searchBackground: '#f5f5f5',
  handleIndicator: '#cccccc',
}}

Layout — one flat prop per element:

selectorSearchContainerStyle={styles.searchBar}
selectorSearchInputStyle={styles.searchText}
selectorCountryItemStyle={{ paddingVertical: 14 }}
selectorListContentContainerStyle={{ paddingBottom: 40 }}

Custom icons & sheet chrome:

selectorRenderSearchIcon={(color) => <MySearch color={color} />}
selectorRenderCheckIcon={(color) => <MyCheck color={color} />}
selectorRenderClearIcon={(color) => <MyClear color={color} />}
selectorBackdropComponent={CustomBackdrop}
selectorBackgroundComponent={CustomBackground}

Country picker (Gorhom sheet)

Props for the default PhoneInput import (Gorhom adapter):

| Prop | Default | Description | |------|---------|-------------| | selectorColors | light/dark defaults | Sheet palette | | selectorContainerStyle | — | Header wrapper of sheet content | | selectorTitleStyle | — | Title text | | selectorSearchContainerStyle | — | Search bar row | | selectorSearchInputStyle | — | Search TextInput | | selectorCountryItemStyle | — | Each country row | | selectorCountryNameStyle | — | Country name label | | selectorCountryCallingCodeStyle | — | Dial code in each row | | selectorListContentContainerStyle | — | List contentContainerStyle | | selectorTitle | localized default | Sheet title | | countryNameLocale | 'en' | Locale for country names ('fr', 'de'…) | | selectorLocale | 'en' | Alias of countryNameLocale | | selectorSnapPoints | ['70%', '100%'] | Sheet snap points | | selectorBackdropComponent | built-in | Custom Gorhom backdrop | | selectorBackgroundComponent | — | Custom sheet background | | selectorRenderSearchIcon | built-in | Custom search icon | | selectorRenderCheckIcon | built-in | Selected-row checkmark | | selectorRenderClearIcon | built-in | Search clear button | | modalSearchInputPlaceholder | localized default | Search placeholder | | modalNotFoundCountryMessage | localized default | Empty list message |

For full control over country rows or search bar JSX, use /headless + CountrySelectorContent.

Custom backdrop:

import { BottomSheetBackdrop } from '@gorhom/bottom-sheet';
import type { BottomSheetBackdropProps } from '@gorhom/bottom-sheet';

const CustomBackdrop = (props: BottomSheetBackdropProps) => (
  <BottomSheetBackdrop {...props} disappearsOnIndex={-1} appearsOnIndex={0} opacity={0.7} />
);

<PhoneInput selectorBackdropComponent={CustomBackdrop} ... />

RTL

<PhoneInput rtl defaultCountry="SA" ... />

Reorders flag, caret, divider, and calling code for right-to-left layouts (Arabic, Hebrew, etc.).


Error state

<PhoneInput
  error
  errorMessage="Invalid phone number"
  ...
/>

Pair with isValidPhoneNumber(phone, country.cca2) from the utilities.


Custom renders

Override individual parts without replacing the whole component:

<PhoneInput
  renderFlag={(country) => <Text>{country?.flag}</Text>}
  renderCallingCode={(country) => <Text>{country?.callingCode}</Text>}
  renderCaretIcon={(color) => <MyChevron color={color} />}
  showCaret={false}
  renderCountryPicker={({ country, onPress, disabled }) => (
    <Pressable onPress={onPress} disabled={disabled}>
      <Text>{country?.cca2}</Text>
    </Pressable>
  )}
/>

Headless mode (custom sheet)

Use headless when you do not want Gorhom as a dependency — e.g. React Native Modal, @lodev09/react-native-true-sheet, or a native bottom sheet.

Minimal install (no Gorhom)

npm install react-native-phone-field react-native-transformer-text-input react-native-worklets

React Native Modal example

import { useState } from 'react';
import { Modal } from 'react-native';
import { PhoneInput } from 'react-native-phone-field/headless';
import { CountrySelectorContent } from 'react-native-phone-field/country-selector';
import type { CountrySelectorImplementation, ICountry } from 'react-native-phone-field/headless';

function useModalCountrySelector(): CountrySelectorImplementation {
  const [visible, setVisible] = useState(false);

  return {
    controller: {
      present: () => setVisible(true),
      dismiss: () => setVisible(false),
    },
    Portal: ({ selectedCountry, onCountrySelect, theme }) => (
      <Modal visible={visible} animationType="slide" onRequestClose={() => setVisible(false)}>
        <CountrySelectorContent
          selectedCountry={selectedCountry}
          theme={theme}
          locale="en"
          onCountrySelect={(country) => {
            onCountrySelect(country);
            setVisible(false);
          }}
        />
      </Modal>
    ),
  };
}
const countrySelector = useModalCountrySelector();

<PhoneInput
  countrySelector={countrySelector}
  value={phone}
  onChangePhoneNumber={setPhone}
  selectedCountry={country}
  onChangeSelectedCountry={setCountry}
/>

Gorhom adapter (headless + Gorhom sheet)

import { useGorhomCountrySelector } from 'react-native-phone-field/sheets/gorhom';
import { PhoneInput } from 'react-native-phone-field/headless';

const countrySelector = useGorhomCountrySelector({
  snapPoints: ['60%', '90%'],
  locale: 'en',
});

<PhoneInput countrySelector={countrySelector} ... />

Utilities

Phone number helpers powered by libphonenumber-js:

import {
  getAllCountries,
  getCountryByCca2,
  getCountryByPhoneNumber,
  getCountriesByCallingCode,
  getCountriesByName,
  formatPhoneNumber,
  isValidPhoneNumber,
  countryCodeToFlag,
} from 'react-native-phone-field';

getCountryByCca2('FR');
// { cca2: 'FR', flag: '🇫🇷', callingCode: '+33', name: 'France' }

getCountryByPhoneNumber('+33612345678');

formatPhoneNumber('0612345678', 'FR');
// "06 12 34 56 78"

isValidPhoneNumber('0612345678', 'FR');

API reference

PhoneInput props (default import)

Includes all core props plus Gorhom selector props (selector*).

Core

| Prop | Type | Required | Description | |------|------|----------|-------------| | value | string | | Controlled national number | | defaultValue | string | | Parse an international number on mount | | onChangePhoneNumber | (phone: string) => void | ✅ | Called on every change | | selectedCountry | ICountry \| null | | Controlled country | | onChangeSelectedCountry | (country: ICountry) => void | ✅ | Called when country changes | | defaultCountry | DefaultCountry | | Initial country ("FR", "US"…) | | theme | 'light' \| 'dark' | | Default: 'light' | | disabled | boolean | | Disables input and picker | | error | boolean | | Error border state | | errorMessage | string | | Shown below input when error | | rtl | boolean | | RTL layout | | placeholder | string | | Overrides auto-placeholder | | countrySelector | CountrySelectorImplementation | | Override default Gorhom picker |

See TypeScript types PhoneInputProps, PhoneInputColors, PhoneInputStyles for the full list.


FAQ

Does this work with Expo?

Yes. The included example app uses Expo. Install peer dependencies and wrap with GorhomPhoneFieldProvider as shown above.

How do I validate a phone number?

import { isValidPhoneNumber } from 'react-native-phone-field';

const valid = country && isValidPhoneNumber(phone, country.cca2);

How do I get the full international number (E.164)?

Combine the calling code with the national number, or use getCountryByPhoneNumber when parsing user input that includes +.

Can I use this without @gorhom/bottom-sheet?

Yes. Import from react-native-phone-field/headless and provide your own countrySelector. Reuse CountrySelectorContent for the searchable country list.

How do I change the country picker language?

Set countryNameLocale="fr" (or any built-in / registered locale). Override selectorTitle, modalSearchInputPlaceholder, and modalNotFoundCountryMessage for UI copy.

Does it support RTL / Arabic?

Yes. Pass rtl on PhoneInput and use countryNameLocale="ar" for Arabic country names.

Is it TypeScript-friendly?

Fully typed exports for props, countries, headless adapters, and selector styles.

What is the difference from react-native-phone-number-input or similar packages?

react-native-phone-field focuses on a modular architecture: default Gorhom sheet, headless mode, reusable CountrySelectorContent, built-in localization for country names, live masking, and granular style/render customization — without locking you into one bottom-sheet implementation.


Troubleshooting

Country picker sheet does not open

Wrap your app with GorhomPhoneFieldProvider (see Quick start).

Sheet backdrop does not cover the status bar

Place GorhomPhoneFieldProvider outside SafeAreaView.

GestureHandlerRootView / Reanimated errors

Install and configure react-native-gesture-handler and react-native-reanimated per their official docs.

TypeScript cannot find exports

Run yarn prepare in the library repo to generate lib/typescript, or reinstall the package.

I don't want Gorhom

Use react-native-phone-field/headless and your own countrySelector (see Headless mode).


Example app

Clone and run the demo (Default, Headless Gorhom, TrueSheet, Modal, custom styles):

git clone https://github.com/asadhmv/react-native-phone-field.git
cd react-native-phone-field
yarn install
yarn example ios   # or: yarn example android

Contributing

License

MIT — see LICENSE.