In this article, we will build an international phone input to allow users to add their country code and country flag before typing their personal phone number.

This component can be used in a sign-up page for a mobile or web application.

The motivation behind this project is that I am currently building my sign up page with React Native. However, I could not find any well-maintained React-Native package to add international phone input to my app.

Hence, I decided to build my own phone input.

Let me show you how I did it.

In this project, besides the Expo SDK, the only third-party library we will be relying on is native-base, which is a React native library for cross-platform user interface (UI) components.

As I myself hate to read articles that blow endless code in your face without the final demo, I decided to show you the end result of what we are going to build in the below link to the video.

React Native phone input with Expo and native-base.

Also, the full code for this project is available in the following repo.

Without further ado, let us get started.

Starting a new Expo project

We will initiate a new Expo app called PhoneInput.

To start a new Expo project, go to your work directory and type the following in the command line.

expo init PhoneInput

You will be prompt to choose a template for your project.

Choose blank and press enter.

After the project is initiated you will see the following.

Access your project root by typing

cd PhoneInput

then install native-base using yarn or npm.

yarn add native-base

Now we are ready to test the app. Start the simulator.

expo start --ios

Or

expo start --android

The Expo app should look like the screenshot below.

Expo default template app.

Now that we bootstrapped a simple Expo app, we are ready to write some JavaScript.

Designing the phone input

Launch your favorite editor and navigate to App.js inside your PhoneInput project.

Expo default template App.js

We will start by adding imports from native-base.

import { StyleSheet, SafeAreaView, View } from 'react-native' // native base imports

import {

Container,

Item,

Input,

Icon

} from 'native-base'

We imported SafeAreaView from react-native to display our components properly on the iPhone X simulator.

Instead of the View component as the root component, we will wrap our components with the SafeAreaView.

export default class App extends React.Component {

render() {

return (

<SafeAreaView style={styles.container}>

<Container style={styles.infoContainer}>

{/* Phone input with native-base */}

<Item rounded style={styles.itemStyle}>

<Icon

active

name='call'

style={styles.iconStyle}

/>

<Input style={styles.inputStyle}/>

</Item>

</Container>

</SafeAreaView>

)

}

}

To make the phone input UI, we added the Container component from native-base in order to style the position and dimensions of the child components.

The phone input field is defined by the Item component which had the rounded property to give curved edges to it.

The Item component wraps an Icon component for the phone icon and an Input component for the text input to add the phone number.

We equipped each component with some styling props that we defined as the following.

const styles = StyleSheet.create({

container: {

flex: 1,

backgroundColor: '#aa73b7',

justifyContent: 'center',

flexDirection: 'column'

},

infoContainer: {

position: 'absolute',

left: 0,

right: 0,

height: 200,

bottom: 250,

flexDirection: 'row',

justifyContent: 'center',

alignItems: 'center',

paddingHorizontal: 30,

backgroundColor: '#aa73b7',

},

iconStyle: {

color: '#5a52a5',

fontSize: 28,

marginLeft: 15

},

itemStyle: {

marginBottom: 10,

},

inputStyle: {

flex: 1,

fontSize: 17,

fontWeight: 'bold',

color: '#5a52a5',

},

})

Refresh the simulator. The app should now look like this.

Basic phone input with native-base.

Easy peasy. Now let us make our phone input look better.

Adding keyboard toggle and dynamic padding behavior

Inside the Item component, add a new Icon for a drop down (rather a modal). This modal, that will be constructing later, will be used to choose the country code and the country flag of the user.

Moreover, inside the Input component, add these additional props to make the phone input look and behave better.

<Icon

active

name='md-arrow-dropdown'

style={[styles.iconStyle, { marginLeft: 0 }]}

/>

<Input

placeholder='+44766554433'

placeholderTextColor='#adb4bc'

keyboardType={'phone-pad'}

returnKeyType='done'

autoCapitalize='none'

autoCorrect={false}

secureTextEntry={false}

style={styles.inputStyle}

/>

Now we want to make the phone input shift in response to the mobile keyboard appearing or disappearing. We also want to dismiss the keyboard every time the user presses done or presses anywhere else on the screen.

To do so, add the following imports to App.js

import React from 'react'

import {

View,

StyleSheet,

SafeAreaView,

Keyboard,

KeyboardAvoidingView,

TouchableWithoutFeedback

} from 'react-native'

Then, inside the render() method, wrap your Container component with a View, a TouchableWithoutFeedback, and a KeyboardAvoidingView from down to top respectively.

<SafeAreaView style={styles.container}>

<KeyboardAvoidingView

style={styles.container}

behavior='padding' enabled >

<TouchableWithoutFeedback

style={styles.container}

onPress={Keyboard.dismiss}>

<View style={styles.container}> <Container style={styles.infoContainer}> ... Same code as before



</Container> </View>

</TouchableWithoutFeedback>

</KeyboardAvoidingView>

</SafeAreaView>

More on these components in the Facebook official docs here, and here.

The final code we wrote so far in App.js is shown in the below gist.

Phone input with keyboard avoiding functionality.

Great, let us have a look at the changes we induced.

In your simulator (I am using Xcode with expo fir iOS), go to Hardware/Keyboard/Toggle Software Keyboard to trigger the device keyboard inside the simulator.

By refreshing the simulator you should observe the below behavior in your app.

Phone input with keyboard toggle and dynamic padding.

Not bad. But we are not there yet.

We want to allow users to choose the country phone code and flag with respect to their country of residence before typing their phone number.

We will then append the remaining phone number sequence that the user will type to the country code they already selected.

So let us get started.

First of all, we need our data source. We will be using JSON data for country code and flags from this link.

Copy the JSON as a JavaScript array into a new file named Countries.js in the root of your app and make it as an export.

const data = [ ... paste the JSON data here] export default data

Now import the data into your App.js.

We want to make a default flag display using the filter() function of JavaScript.

import data from './Countries' // Default render of country flag

const defaultFlag = data.filter(

obj => obj.name === 'United Kingdom'

)[0].flag export default class App extends React.Component {

state = {

flag: defaultFlag

}

render() {

We stored the flag in the App state as this piece of data will be changed by the user.

Add the following View inside the Item component.

<Item rounded style={styles.itemStyle}>

<Icon

active

name='call'

style={styles.iconStyle}

/>

{/* country flag */}

<View><Text>{this.state.flag}</Text></View> ... Same code as before </Item>

The default flag component should render like this

Phone input with the default country flag.

Updating the flag and country code

Now for the user to change to their country flag and country code, we will add two additional fields to the state

state = {

flag: defaultFlag,

modalVisible: false,

phoneNumber: '',

}

To toggle the modal with the list of countries, we will import the Modal, TouchableOpacity, and the FlatList components from ‘react-native’.

import {

View,

Text,

...

Modal,

FlatList,

TouchableOpacity

} from 'react-native'

We will toggle the Modal by defining two methods above the render().

showModal() {

this.setState({ modalVisible: true })

} hideModal() {

this.setState({ modalVisible: false })

}

The above code is self-explanatory. One method sets the state of modalVisible to true to make it appear and the other hides the Modal by setting modalVisible to false.

We want the text to refocus on the phone Input after the user selects the country code. I find that the best way to do this is by adding the following line of code (based on this thread).

hideModal() {

this.setState({ modalVisible: false })

// Refocus on the Input field after selecting the country code

this.refs.PhoneInput._root.focus()

}

We also need to define a method that takes the selected country from the user as its argument, filters the countryData imported from Countries.js using the filter function of JavaScript, and then stores its corresponding flag and country code in the flag and phoneNumber state fields respectively.

We call this method selectCountry().

async selectCountry(country) { // Get data from Countries.js

const countryData = await data try {

// Get the country code

const countryCode = await countryData.filter(

obj => obj.name === country

)[0].dial_code // Get the country flag

const countryFlag = await countryData.filter(

obj => obj.name === country

)[0].flag // Update the state then hide the Modal

this.setState({ phoneNumber: countryCode, flag: countryFlag })

await this.hideModal()

}

catch (err) {

console.log(err)

}

}

Notice that the hideModal() method is called after we update the state. This way the Modal will disappear once users selected their country of choice.

One last method is needed. You might have guessed it if you are familiar with React Native 😉.

onChangeText(key, value) {

this.setState({

[key]: value

})

}

onChangeText will take the user text input and store it in the appropriate state field. In our case, it will append the phone number to the country code and store the whole sequence in the phoneNumber state field.

All we need to do now is update the render() method to include the Modal component and its corresponding event handlers.

First of all, we store the data array of countries inside a variable we call countryData. This variable will act as our data source for the FlatList component. More on Flatlists in the official docs here.

render() {

const countryData = data

... Rest of the code

}

Inside the Item component, add the following code below the Input component.

{/* Modal for country code and flag */}

<Modal

animationType="slide"

transparent={false}

visible={this.state.modalVisible}>

<View style={{ flex: 1 }}>

<View style={{ flex: 7, marginTop: 80 }}>

{/* Render the list of countries */}

<FlatList

data={countryData}

keyExtractor={(item, index) => index.toString()}

renderItem={

({ item }) =>

<TouchableWithoutFeedback onPress={() => this.selectCountry(item.name)}>

<View style={styles.countryStyle}>

<Text style={styles.textStyle}>

{item.flag} {item.name} ({item.dial_code})

</Text>

</View>

</TouchableWithoutFeedback>

}

/>

</View>

<TouchableOpacity

onPress={() => this.hideModal()}

style={styles.closeButtonStyle}>

<Text style={styles.textStyle}>

Cancel

</Text>

</TouchableOpacity>

</View>

</Modal>

We are rendering the countryData using the FlatList component. For each element of the countryData, we display the country name, flag, and phone code.

We wrapped the countryData list of items with a TouchableWithoutFeedback. Its onPress calls the selectCountry method. When selectCountry is called, we store the country code in the phoneNumber state.

Finally, we added a TouchableOpacity to hide the Modal in case the user wants to cancel this action.

Now go back to the Input and the Icon components located above the Modal component and add the following fields (marked in bold).

<Icon

active

name='md-arrow-dropdown'

style={[styles.iconStyle, { marginLeft: 0 }]}

onPress={() => this.showModal()}

/>

<Input

placeholder='+44766554433'

placeholderTextColor='#adb4bc'

keyboardType={'phone-pad'}

returnKeyType='done'

autoCapitalize='none'

autoCorrect={false}

secureTextEntry={false}

style={styles.inputStyle}

value={this.state.phoneNumber}

ref='PhoneInput'

onChangeText={(val) => this.onChangeText('phoneNumber', val)}

/>

The Modal is shown when the user presses the dropdown Icon.

After users choose their country, selectCountry calls the hideModal method and the Modal disappears. At the same time, the text is refocused on the Input component (ref=’PhoneInput’).

Adding the user phone number

At this state, the phoneNumber field has a country code attached to it.

When the user types the phone number, the onChangeText method will complete updating the phoneNumber field by calling setState().

The final styling of the app is displayed in the following gist.

Ok, I think it is time to test our code in the simulator.

You should be able to see the final behavior like in the below video.

React Native phone input with Expo and native-base.

Conclusion

International phone input is a major component in modern web and mobile application sign up pages. Due to the lack of React Native components that serve this utility, I decided to show you how I build my own in this article.

That’s it. I hope you enjoyed this read.

If you did enjoy this tutorial, you can give me as many claps👏 as 50. Hit the follow button to stay updated with the upcoming articles. You can stay updated with my latest open source projects on Twitter and Github.

See you soon ✋.

Join our community Slack and read our weekly Faun topics ⬇