Skip to content

Latest commit

Β 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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 helpers β€” isValidPhoneNumber, formatPhoneNumber, getCountryByPhoneNumber
  • Localized country names β€” countryNameLocale 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.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages