@linhnguyen96114/react-native-phone-input
v3.9.0
Published
React Native component for phone number
Maintainers
Readme
✨ Features
- 📱 Cross-platform support (iOS & Android)
- 🎨 Highly customizable UI
- 🔍 Built-in country search
- ✅ Google LibPhoneNumber validation
- 🎯 TypeScript support
- 🔄 Two flexible layouts
- 🏳️ Country emoji flags support
- 📞 Automatic country detection
- 🎨 Dark theme support
- 🎭 Country-specific phone number masking
- 🔧 Extensive API
🚀 Installation
npm install @linhnguyen96114/react-native-phone-input
# For iOS
cd ios && pod installRequires React >=19.0.0 and React Native >=0.87.0, plus react-native-safe-area-context.
Upgrading from 3.x? See the migration guide — value is now a real controlled
prop and onChangeFormattedText emits proper E.164.
💡 Examples
Basic Usage
import PhoneInput from "@linhnguyen96114/react-native-phone-input";
const BasicExample = () => {
const [value, setValue] = useState("");
return <PhoneInput value={value} defaultCode="US" onChangeText={setValue} withShadow autoFocus />;
};Custom Styled Input
const CustomStyledExample = () => {
const [value, setValue] = useState("");
return (
<PhoneInput
value={value}
defaultCode="US"
onChangeText={setValue}
containerStyle={{
width: "100%",
borderRadius: 30,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 3
}}
textContainerStyle={{
borderRadius: 30,
backgroundColor: "#fff",
paddingHorizontal: 15
}}
/>
);
};Dark Theme
const DarkThemeExample = () => {
const [value, setValue] = useState("");
return (
<PhoneInput
value={value}
defaultCode="GB"
onChangeText={setValue}
withDarkTheme
containerStyle={{
backgroundColor: "#2A2A2A",
borderRadius: 12
}}
textContainerStyle={{
backgroundColor: "#2A2A2A",
borderRadius: 12
}}
textInputStyle={{
color: "#fff"
}}
/>
);
};Form Integration with Validation
const FormExample = () => {
const [value, setValue] = useState("");
const [valid, setValid] = useState(false);
const phoneInput = useRef<PhoneInputRefType>(null);
const checkValidation = () => {
const isValid = phoneInput.current?.isValidNumber(value);
setValid(isValid || false);
};
return (
<PhoneInput
ref={phoneInput}
value={value}
defaultCode="FR"
onChangeText={setValue}
onChangeFormattedText={(text) => {
console.log("Formatted:", text);
}}
containerStyle={{
width: "100%",
borderRadius: 8,
borderWidth: 1,
borderColor: valid ? "#4CAF50" : "#dee2e6"
}}
/>
);
};Phone Number Masking
const MaskingExample = () => {
const [value, setValue] = useState("");
const [formattedValue, setFormattedValue] = useState("");
return (
<PhoneInput
value={value}
defaultCode="US"
onChangeText={setValue}
onChangeFormattedText={setFormattedValue}
withMask
withShadow
containerStyle={{
width: "100%",
borderRadius: 12
}}
/>
);
};
// User types: 1234567890
// Display shows: (123) 456-7890
// onChangeText receives: "1234567890"
// onChangeFormattedText receives: "+11234567890"🛠️ Props
| Prop | Type | Description |
| -------------------------- | ---------------------------- | ------------------------------------- |
| withDarkTheme | boolean | Enable dark theme |
| withShadow | boolean | Add shadow effect |
| withMask | boolean | Enable country-specific phone masking |
| autoFocus | boolean | Auto focus input |
| defaultCode | CountryCode | Default country code |
| defaultCallingCode | string | Default calling code |
| value | string | Controlled value; supplying it at mount makes the component controlled for life |
| defaultValue | string | Uncontrolled seed, read once at mount |
| disabled | boolean | Disable input |
| disableArrowIcon | boolean | Hide the dropdown arrow icon |
| placeholder | string | Input placeholder text |
| onChangeCountry | (country: Country) => void | Callback when country changes |
| onChangeText | (text: string) => void | Callback when input text changes |
| onChangeFormattedText | (text: string) => void | Callback with formatted phone number |
| onBlur | () => void | Callback when input loses focus |
| onFocus | () => void | Callback when input gains focus |
| renderDropdownImage | React.ReactNode | Custom dropdown icon component |
| containerStyle | StyleProp<ViewStyle> | Container style |
| textContainerStyle | StyleProp<ViewStyle> | Text input container style |
| textInputProps | TextInputProps | Additional TextInput props |
| textInputStyle | StyleProp<TextStyle> | Text input style |
| codeTextStyle | StyleProp<TextStyle> | Country code text style |
| flagButtonStyle | StyleProp<ViewStyle> | Flag button container style |
| countryPickerButtonStyle | StyleProp<ViewStyle> | Country picker button style |
| layout | "first" \| "second" | Layout style |
| filterProps | CountryFilterProps | Country filter props |
| countryPickerProps | Partial<CountryPickerModalProps> | Country picker modal props; countryCode and onSelect are set internally |
| flagSize | number | Size of the country flag |
| flagContainerStyle | StyleProp<ViewStyle> | Flag's own container style, merged after the default (width: 30, marginRight: 10) |
| flagButtonAutoWidth | boolean | Skip the button's responsive width (20%/23% of the window) and size it to its content instead. Default false |
| showCountryCode | boolean | Show the country code |
🔧 Methods
| Method | Return Type | Description |
| --------------------------------------- | ---------------------------------------------- | --------------------------------------------------------- |
| getCountryCode | CountryCode | Get the currently selected country code |
| getCallingCode | CallingCode \| undefined | Get the calling code for the selected country |
| isValidNumber | boolean | Validate if the provided phone number is valid |
| getNumberAfterPossiblyEliminatingZero | { number: string \| undefined; formattedNumber: string \| undefined; } | number has a leading zero stripped; formattedNumber is E.164 and keeps the zero where the region requires it |
🤝 Contributing
Contributions are welcome! Please read our contributing guide to learn about our development process.
📝 License
This project is MIT licensed.
