
React Native International Phone Number Input
Features
- 🌎 Phone Input Mask – Auto-formatting per selected country
- ✅ Validation - Check phone number;
- 📱 Cross-Platform – Works seamlessly on iOS, Android and Web;
- 🧩 Flexible Integration – Supports both React Native CLI & Expo;
- 👨💻 Component Versatility - Works with functional & class components;
- 🎨 Modern UI - Custom component with sleek design;
- 🈶 internationalization - Supports 32 languages;
- 🧪 Test Ready – Smooth testing integration;
- ♿ Accessibility – Accessibility standards to screen readers.
Try it out
List of Contents
- Old Versions
- Installation
- Additional Config to WEB
- Basic Usage
- Intermediate Usage
- Advanced Usage
- Customizing Lib
- Lib Props
- Lib Functions
- Supported languages
- Testing
- Accessibility
- Contributing
- License
Old Versions
Installation
$ npm i --save react-native-international-phone-number
OR
$ yarn add react-native-international-phone-number
Additional config to WEB
Using React Native CLI:
Create a react-native.config.js
file at the root of your react-native project with:
module.exports = {
project: {
ios: {},
android: {},
},
assets: [
'./node_modules/react-native-country-select/lib/assets/fonts',
],
};
Then link the font to your native projects with:
npx react-native-asset
Using Expo:
Install expo-fonts:
npx expo install expo-font
;- Initialize the
expo-font
:
import { useFonts } from 'expo-font';
...
useFonts({
'TwemojiMozilla': require('./node_modules/react-native-country-select/lib/assets/fonts/TwemojiMozilla.woff2'),
});
...
Observation: you need to recompile your project after adding new fonts.
Basic Usage
Class Component:
import React from 'react';
import { View, Text } from 'react-native';
import PhoneInput, { isValidPhoneNumber } from 'react-native-international-phone-number';
export class App extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedCountry: null,
inputValue: ''
}
}
function handleSelectedCountry(country) {
this.setState({
selectedCountry: country
})
}
function handleInputValue(phoneNumber) {
this.setState({
inputValue: phoneNumber
})
}
render(){
return (
<View style={{ width: '100%', flex: 1, padding: 24 }}>
<PhoneInput
value={this.state.inputValue}
onChangePhoneNumber={this.handleInputValue}
selectedCountry={this.state.selectedCountry}
onChangeSelectedCountry={this.handleSelectedCountry}
/>
<View style={{ marginTop: 10 }}>
<Text>
Country:{' '}
{`${this.state.selectedCountry?.translations?.eng?.common} (${this.state.selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${this.state.selectedCountry?.idd?.root} ${this.state.inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(this.state.inputValue, this.state.selectedCountry)
? 'true'
: 'false'}
</Text>
</View>
</View>
);
}
}
Function Component:
import React, {useState} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
isValidPhoneNumber,
} from 'react-native-international-phone-number';
export default function App() {
const [selectedCountry, setSelectedCountry] = useState(null);
const [inputValue, setInputValue] = useState('');
function handleInputValue(phoneNumber) {
setInputValue(phoneNumber);
}
function handleSelectedCountry(country) {
setSelectedCountry(country);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput
value={inputValue}
onChangePhoneNumber={handleInputValue}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
<View style={{marginTop: 10}}>
<Text>
Country:{' '}
{`${selectedCountry?.translations?.eng?.common} (${selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${selectedCountry?.idd?.root} ${inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(inputValue, selectedCountry) ? 'true' : 'false'}
</Text>
</View>
</View>
);
}
Typescript
import React, {useState} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
ICountry,
isValidPhoneNumber,
} from 'react-native-international-phone-number';
export default function App() {
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
const [inputValue, setInputValue] = useState<string>('');
function handleInputValue(phoneNumber: string) {
setInputValue(phoneNumber);
}
function handleSelectedCountry(country: ICountry) {
setSelectedCountry(country);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput
value={inputValue}
onChangePhoneNumber={handleInputValue}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
<View style={{marginTop: 10}}>
<Text>
Country:{' '}
{`${selectedCountry?.translations?.eng?.common} (${selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${selectedCountry?.idd?.root} ${inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(inputValue, selectedCountry) ? 'true' : 'false'}
</Text>
</View>
</View>
);
}
Intermediate Usage
Typescript + useRef
import React, {useRef} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
ICountry,
IPhoneInputRef,
} from 'react-native-international-phone-number';
export default function App() {
const phoneInputRef = useRef<IPhoneInputRef>(null);
function onSubmitRef() {
Alert.alert(
'Intermediate Result',
`Country: ${inputRef.current?.selectedCountry?.translations?.eng?.common} \nPhone Number: ${inputRef.current?.fullPhoneNumber} \nisValid: ${inputRef.current?.isValid}`,
);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput ref={phoneInputRef} />
<TouchableOpacity
style={{
width: '100%',
paddingVertical: 12,
backgroundColor: '#2196F3',
borderRadius: 4,
marginTop: 10,
}}
onPress={onSubmit}>
<Text
style={{
color: '#F3F3F3',
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
}}>
Submit
</Text>
</TouchableOpacity>
</View>
);
}
Observation: Don't use the useRef hook combined with the useState hook to manage the phoneNumber and selectedCountry values. Instead, choose to use just one of them (useRef or useState).
Advanced Usage
React-Hook-Form + Typescript + Default Phone Number Value
import React, {useState, useEffect} from 'react';
import {View, Text, TouchableOpacity, Alert} from 'react-native';
import PhoneInput, {
ICountry,
isValidPhoneNumber,
} from 'react-native-international-phone-number';
import {Controller, FieldValues} from 'react-hook-form';
interface FormProps extends FieldValues {
phoneNumber: string;
}
export default function App() {
const [selectedCountry, setSelectedCountry] = useState<undefined | ICountry>(
undefined,
);
function handleSelectedCountry(country: ICountry) {
setSelectedCountry(country);
}
function onSubmit(form: FormProps) {
const phoneNumber = `${selectedCountry?.idd?.root} ${form.phoneNumber}`;
const isValid = isValidPhoneNumber(
form.phoneNumber,
selectedCountry as ICountry,
);
Alert.alert(
'Advanced Result',
`Country: ${selectedCountry?.translations?.eng?.common} \nPhone Number: ${phoneNumber} \nisValid: ${isValid}`,
);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<Controller
name="phoneNumber"
control={control}
render={({field: {onChange, value}}) => (
<PhoneInput
defaultValue="+12505550199"
value={value}
onChangePhoneNumber={onChange}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
)}
/>
<TouchableOpacity
style={{
width: '100%',
paddingVertical: 12,
backgroundColor: '#2196F3',
borderRadius: 4,
}}
onPress={handleSubmit(onSubmit)}>
<Text
style={{
color: '#F3F3F3',
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
}}>
Submit
</Text>
</TouchableOpacity>
</View>
);
}
Observations:
- You need to use a default value with the following format:
+(country callling code)(area code)(number phone)
- The lib has the mechanism to set the flag and mask of the supplied
defaultValue
. However, if the supplieddefaultValue
does not match any international standard, theinput mask of the defaultValue
will be set to "BR" (please make sure that the default value is in the format mentioned above).
Customizing lib
PhoneInput Styles (phoneInputStyles)
Property | Type | Description |
---|---|---|
container |
ViewStyle | Main input container |
flagContainer |
ViewStyle | Flag and dropdown container |
flag |
TextStyle | Flag emoji styling |
caret |
TextStyle | Dropdown arrow |
divider |
ViewStyle | Separator line |
callingCode |
TextStyle | Country calling code |
input |
TextStyle | Phone number input |
Modal Styles (modalStyles)
Property | Type | Description |
---|---|---|
backdrop |
ViewStyle | Modal background overlay |
container |
ViewStyle | Modal main container |
content |
ViewStyle | Modal content area |
searchContainer |
ViewStyle | Search input wrapper |
searchInput |
TextStyle | Search input field |
list |
ViewStyle | Countries list container |
countryItem |
ViewStyle | Individual country row |
flag |
TextStyle | Country flag in list |
countryInfo |
ViewStyle | Country details container |
callingCode |
TextStyle | Calling code in list |
countryName |
TextStyle | Country name in list |
sectionTitle |
TextStyle | Section headers |
closeButton |
ViewStyle | Close button container |
closeButtonText |
TextStyle | Close button text |
countryNotFoundContainer |
ViewStyle | No results container |
countryNotFoundMessage |
TextStyle | No results message |
Component Props (PhoneInputProps)
Prop | Type | Description | |
---|---|---|---|
theme |
ITheme |
Theme configuration for the component | |
language |
ILanguage |
Language for country names and UI | |
defaultValue |
string |
Default phone number value (format: +(country code)(area code)(number) ) |
|
value |
string |
Controlled phone number value | |
onChangePhoneNumber |
(phoneNumber: string) => void |
Callback when phone number changes | |
defaultCountry |
ICountryCca2 |
Default selected country (ISO 3166-1 alpha-2) | |
selectedCountry |
ICountry |
Currently selected country object | |
onChangeSelectedCountry |
(country: ICountry) => void |
Callback when country selection changes | |
placeholder |
string |
Placeholder text for phone input | |
phoneInputPlaceholderTextColor |
string |
Color of placeholder text | |
phoneInputSelectionColor |
string |
Color of text selection | |
phoneInputStyles |
IPhoneInputStyles |
Custom styles for phone input component | |
modalStyles |
ICountrySelectStyles |
Custom styles for country selection modal | |
disabled |
boolean |
Disable the entire phone input | |
modalDisabled |
boolean |
Disable only the country selection modal | |
visibleCountries |
ICountryCca2[] |
Array of country codes to show in modal | |
hiddenCountries |
ICountryCca2[] |
Array of country codes to hide from modal | |
popularCountries |
ICountryCca2[] |
Array of country codes to show in popular section | |
customCaret |
() => ReactNode |
Custom dropdown arrow component | |
rtl |
boolean |
Enable right-to-left layout | |
isFullScreen |
boolean |
Show modal in full screen mode | |
modalType |
`'bottomSheet' \ | 'popup'` | Type of modal presentation |
modalSearchInputPlaceholderTextColor |
string |
Color of modal search placeholder text | |
modalSearchInputPlaceholder |
string |
Placeholder text for modal search input | |
modalSearchInputSelectionColor |
string |
Color of modal search text selection | |
modalPopularCountriesTitle |
string |
Title for popular countries section | |
modalAllCountriesTitle |
string |
Title for all countries section | |
modalSectionTitleComponent |
() => ReactNode |
Custom section title component | |
modalCountryItemComponent |
() => ReactNode |
Custom country item component | |
modalCloseButtonComponent |
() => ReactNode |
Custom close button component | |
modalSectionTitleDisabled |
boolean |
Disable section titles in modal | |
modalNotFoundCountryMessage |
string |
Message when no countries found | |
disabledModalBackdropPress |
boolean |
Disable modal close on backdrop press | |
removedModalBackdrop |
boolean |
Remove modal backdrop entirely | |
onModalBackdropPress |
() => void |
Callback when modal backdrop is pressed | |
onModalRequestClose |
() => void |
Callback when modal close is requested | |
showModalSearchInput |
boolean |
Show search input in modal | |
showModalCloseButton |
boolean |
Show close button in modal | |
showModalScrollIndicator |
boolean |
Show scroll indicator in modal | |
ref |
Ref<IPhoneInputRef> |
Ref to access component methods |
Functions
Function | Parameters | Return Type | Description | |
---|---|---|---|---|
getAllCountries |
() |
ICountry[] |
Returns an array of all available countries | |
getCountriesByCallingCode |
(callingCode: string) |
`ICountry[] \ | undefined` | Returns countries that match the given calling code |
getCountryByCca2 |
(cca2: string) |
`ICountry \ | undefined` | Returns a country by its ISO 3166-1 alpha-2 code |
getCountriesByName |
(name: string, language: ILanguage) |
`ICountry[] \ | undefined` | Returns countries that match the given name in the specified language |
getCountryByPhoneNumber |
(phoneNumber: string) |
`ICountry \ | undefined` | Returns the country that matches the given phone number |
isValidPhoneNumber |
(phoneNumber: string, country: ICountry) |
boolean |
Validates if a phone number is valid for the given country |
Supported languages
The language
prop supports the following values:
Code | Language |
---|---|
ara |
Arabic |
bel |
Belarusian |
bre |
Breton |
bul |
Bulgarian |
ces |
Czech |
deu |
German |
ell |
Greek |
eng |
English |
est |
Estonian |
fin |
Finnish |
fra |
French |
heb |
Hebrew |
hrv |
Croatian |
hun |
Hungarian |
ita |
Italian |
jpn |
Japanese |
kor |
Korean |
nld |
Dutch |
per |
Persian |
pol |
Polish |
por |
Portuguese |
ron |
Romanian |
rus |
Russian |
slk |
Slovak |
spa |
Spanish |
srp |
Serbian |
swe |
Swedish |
tur |
Turkish |
ukr |
Ukrainian |
urd |
Urdu |
zho |
Chinese |
zho-Hans |
Simplified Chinese |
zho-Hant |
Traditional Chinese |
Testing
When utilizing this package, you may need to target the PhoneInput component in your automated tests. To facilitate this, we provide a testID props for the PhoneInput component. The testID can be integrated with popular testing libraries such as @testing-library/react-native or Maestro. This enables you to efficiently locate and interact with PhoneInput elements within your tests, ensuring a robust and reliable testing experience.
const phoneInput = getByTestId('countryPickerPhoneInput');
const flagContainerButton = getByTestId('countryPickerFlagContainerButton');
const countrySelect = getByTestId('countrySelectSearchInput');
const countrySelectBackdrop = getByTestId('countrySelectBackdrop');
const countrySelectList = getByTestId('countrySelectList');
const countrySelectSearchInput = getByTestId('countrySelectSearchInput');
const countrySelectItem = getByTestId('countrySelectItem');
const countrySelectCloseButton = getByTestId('countrySelectCloseButton');
Accessibility
Ensure your app is inclusive and usable by everyone by leveraging built-in React Native accessibility features. The accessibility props are covered by this package.
Contributing
- Fork or clone this repository
$ git clone https://github.com/AstrOOnauta/react-native-international-phone-number.git
Repair, Update and Enjoy 🛠️🚧⚙️
Create a new PR to this repository
License
Thanks for stopping by! 😁