The form is a very basic need for any website or application. And form validation is required to collect the right information. In this article, we are going to learn Form validation with Formik and Yup for React Native application.
Let’s start by creating a new project with expo CLI, we are going to name it form-validation. You can use any name for your project.
expo init form-validation
The above command will create and set up everything that we require to run our application. Now move to your project directory and check that everything is fine by running your project.
expo start
Install Formik and Yup
The next step is to install the Formik and Yup for the Form Validation. We are going to use the React Native Elements package to quickly set up the UI for our Form. Let’s install the dependencies through the npm command.
npm install react-native-elements formik yup
Create Reusable Components
It’s best practice to create the component for the reusable elements. In our case, we need the heading, input field, and the button component. Let’s create reusable components for the followings.
Let’s first create a components directory to your project directory and create the following files i.e. Heading.js
, InputField.js
and InputButton.js
Heading Component
Open the Heading.js
file and add the following code.
import React from 'react'
import { Text } from 'react-native-elements'
import { StyleSheet } from 'react-native'
const Heading = ({ title, ...size }) => (
<Text {...size} style={styles.heading}>{ title }</Text>
)
const styles = StyleSheet.create({
heading: {
color: '#533263',
fontWeight: 'bold'
}
});
export default Heading
The above codes work similarly to the “HMTL headings” that support the H1-H6 and a title property to display the text.
InputField Component
Paste the following codes to the InputField.js
file.
import React from 'react'
import { Input } from 'react-native-elements'
import { StyleSheet, View } from 'react-native'
import { Ionicons } from '@expo/vector-icons'
const InputField = ({ iconName, iconColor, name, placeholder, label, value, ...rest }) => (
<View style={styles.container}>
<Input
{...rest}
leftIcon={<Ionicons name={iconName} size={28} color={iconColor} />}
leftIconContainerStyle={styles.iconStyle}
placeholderTextColor='grey'
name={name}
value={value}
label={label}
placeholder={placeholder}
style={styles.input}
/>
</View>
)
const styles = StyleSheet.create({
container: {
marginBottom: 15,
width: '100%'
},
iconStyle: {
marginRight: 10
}
})
export default InputField;
Basically, we reconstructed the react-native-elements Input component as per our application UI. We supported the following properties for component i.e. iconName
, iconColor
, name
, placeholder
, label
, value
. The ...rest
property for all the properties that we have not defined but can be supported by our component.
InputButton Component
Now open the InputButton.js
file and paste the following code.
import React from 'react'
import { Button } from 'react-native-elements'
const InputButton = ({ title, buttonType, buttonColor, ...rest }) => (
<Button
{...rest}
type={buttonType}
title={title}
buttonStyle={{ borderColor: buttonColor, borderRadius: 3 }}
titleStyle={{ color: '#ffffff' }}
/>
)
export default InputButton
It’s similar to the InputField component, but this time we have reconstructed the Button component.
Create Sign Up Screen
We are going to create a Sign-Up Form for our application with validation. This is how our Signup screen going to look alike.
Let’s start to create the signup screen by adding the following dependencies and components to the App.js
file.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import InputField from './components/InputField'
import InputButton from './components/InputButton'
import Heading from './components/Heading'
Next, add some style to manage the Signup form UI.
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FAFBFE',
alignItems: 'center',
justifyContent: 'center',
},
heading: {
color: '#533263',
fontWeight: 'bold'
},
form: {
width: '90%',
marginTop: 50
},
});
Now, let’s work on the main form. First, add a container with the help of View
(Native component) that holds the entire screen. Set the title “Signup Form” with the help of the Heading
component under the parent View
component.
export default function App() {
return (
<KeyboardAvoidingView style={styles.avoidKeyboard} behavior="padding" enabled keyboardVerticalOffset={85}>
<View style={styles.container}>
<Heading h2 title="Signup Form" />
</View>
</KeyboardAvoidingView>
)
}
KeyboardAvoidingView: We are using this component to avoid view to overlap with keyboard
The next step is to create a form container that holds the entire form design that we are going to create through with the help of InputField
and the InputButton
component. We are going to add the Fullname, Email and Password fields for this Signup form.
<View style={styles.form}>
<InputField
name='fullname'
label='Full Name'
placeholder='Enter your name'
autoCapitalize='none'
iconName='ios-person'
iconColor='#533263'
/>
<InputField
name='email'
label='Email Address'
placeholder='Enter email'
keyboardType='email-address'
returnKeyType='done'
autoCapitalize='none'
iconName='ios-mail'
iconColor='#533263'
/>
<InputField
name='password'
label='Password'
placeholder='Enter password'
autoCapitalize='none'
secureTextEntry={true}
iconName='ios-lock'
iconColor='#533263'
/>
<InputButton
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
/>
</View>
Add Formik to Signup Form
We have completed the Form design. Now its time to implement the form validation process. We are going to use the Formik for form validation. We need to import the Formik to our App.js
file.
import { Formik } from 'formik'
Now it’s time to define the initial values and onSubmit event handler.
<Formik
initialValues={{
fullname: '',
email: '',
password: ''
}}
onSubmit={values => {}}>
{() => (
<>
....
....
....
</>
)}
</Formik>
As you see in the above codes, we have defined three initial values that are corresponding to the FullName, Email, and Password fields. The onSubmit event is mapped with the handleSubmit
event through Formik. We are going to learn about it to the next section.
Now let’s return our form through Formik. Through this, we will have access to the pre-defined Formik properties such as handleChange
, values
, handleSubmit
, etc.
{({handleChange, values, handleSubmit}) => (
<>
<InputField
name='fullname'
label='Full Name'
value={values.fullname}
onChangeText={handleChange('fullname')}
placeholder='Enter your name'
autoCapitalize='none'
iconName='ios-person'
iconColor='#533263'
/>
....
....
<InputButton
onPress={handleSubmit}
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
/>
</>
)}
As you can see to the above codes, we have used the values.fullname
with the InputField value
property that helps to keep updated data for the particular field. Same we used the handleChange
event with onChangeText event handler to keep the updated value during the input for the particular state i.e. fullname
.
The InputButton event is simply straight forwarded and it works with the onPress
that is mapped with handleSubmit
Formik event property.
Validate React Native Form With Yup
The next step is to define the validation rules for our initialValues
that we have defined with the Formik package. We are going to use the Yup package and let’s import it to the App.js
file.
import * as Yup from 'yup'
Next, let’s add the predefined rules to the initialValues
i.e. fullname
, email
and password
.
const validationSchema = Yup.object().shape({
fullname: Yup.string()
.label('Fullname')
.required('Please enter your name'),
email: Yup.string()
.label('Email')
.email('Enter a valid email')
.required('Please enter your email address'),
password: Yup.string()
.label('Password')
.required('Please enter your password')
.min(4, 'Password must have at least 4 characters ')
})
Formik has a property i.e. validationSchema
that accepts schema that could be Yup schema or a function that returns the Yup schema. We are going to use the property to map with Yup validation schema. Through this property, the returned errors are automatically mapped to the inner component i.e. errors
.
<Formik
initialValues={{
fullname: '',
email: '',
password: ''
}}
onSubmit={values => {}}
validationSchema={validationSchema}>
{({handleChange, values, handleSubmit, errors}) => (
<>
....
....
....
....
</>
)}
</Formik>
Create a component for error message
Time to create another component to handle errors that match our design we name it ErrorMessage.
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
const ErrorMessage = ({ errorValue }) => (
<View style={styles.container}>
<Text style={styles.errorText}>{errorValue}</Text>
</View>
)
const styles = StyleSheet.create({
container: {
marginLeft: 10
},
errorText: {
color: 'red'
}
})
export default ErrorMessage
This is how we used our ErrorMessage component to handle the given errors by Yup validation schema.
<>
<InputField
name='fullname'
label='Full Name'
value={values.fullname}
onChangeText={handleChange('fullname')}
placeholder='Enter your name'
autoCapitalize='none'
iconName='ios-person'
iconColor='#533263'
/>
<ErrorMessage errorValue={errors.fullname} />
....
....
<InputButton
onPress={handleSubmit}
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
/>
</>
Disable Button Until Form Not Valid
Let’s move to the next step to disable the button until the form not valid and during the submitting process. We are going to use other Formik properties i.e. isValid
and isSubmitting
. Both properties will return the boolean value for the particular action. Like isValid
returns true
if the form validation complete otherwise it returns false
. This is how we can use it to our InputButton component with the disabled
property.
{({handleChange, values, handleSubmit, errors, isValid, isSubmitting}) => (
<>
....
....
....
....
<InputButton
onPress={handleSubmit}
disabled={! isValid || isSubmitting}
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
/>
</>
)}
Display Error For Specified Field
Previously, we have added the ErrorMessage component to display the error in our React Native application. But it’s a little embarrassing to display all the errors at the same time. We can display the error message for the specified filed instead of all at once.
We are going to use the touched
and handleBlur
Formik properties. The touched
property contains the initial values as property and returns boolean
during the active field. The handleBlur
event handler is going to use with onBlur
event. Take a look to the below codes.
{({handleChange, values, handleSubmit, errors, isValid, isSubmitting, touched, handleBlur}) => (
<>
<InputField
name='fullname'
label='Full Name'
value={values.fullname}
onChangeText={handleChange('fullname')}
onBlur={handleBlur('fullname')}
placeholder='Enter your name'
autoCapitalize='none'
iconName='ios-person'
iconColor='#533263'
/>
<ErrorMessage errorValue={touched.fullname && errors.fullname} />
....
....
<InputButton
onPress={handleSubmit}
disabled={! isValid || isSubmitting}
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
/>
</>
)}
Display Loading Indicator While Submiting
The final step is to add the loading indicator to our screen. We already have the isSubmitting
Formik property that invokes with the onSubmit
event.
<InputButton
onPress={handleSubmit}
disabled={! isValid || isSubmitting}
buttonType='solid'
title='SIGN UP'
buttonColor='#533263'
loading={ isSubmitting }
/>
We hope this article will help you to implement form validation in your React Native application. If you like this article then please follow us on Facebook and Twitter.