React Native Form Validation

Last Updated Jun 15, 2022
Elizabeth (Lizzie) Shipton

Lizzie is a Full Stack Engineer at Udacity and freelance technical content writer. She has experience working with Node, GraphQL, Postgres, React and Sass.

Table of Contents:

If you’re developing your latest mobile app with React Native, validation and form-building is easy. 

React Native provides a framework to build cross-platform mobile apps using React JS code. It’s extremely easy to get started, and there are plenty of libraries available to help you do common things like build forms. You can also use many of the same libraries that you would use to build a regular React app.

In this article, we will explore how to do form with validation in React Native. We'll cover a few different methods for form creation and validation, including Native Components, Formik and Yup, and React Hook Form.

Don't reinvent the wheel.
Abstract's APIs are production-ready now.

Abstract's suite of API's are built to save you time. You don't need to be an expert in email validation, IP geolocation, etc. Just focus on writing code that's actually valuable for your app or business, and we'll handle the rest.

Get started for free

Why is Data Validation Important?

Validation prevents improperly formatted data from entering your app’s database or other information systems. It also helps to prevent bad actors from injecting scripts into the application’s form input fields.

Client-side validation is the first line of defense in data validation. Performing client-side validation means making sure all the form fields on the UI have been correctly filled out and formatted, and that the form does not contain any malicious data.

Once we determine that all validation parameters are met, we send the information to the server.

Getting Started With React Native

Some familiarity with React Native will be helpful for this article, but not required. First, let’s spin up a simple React Native App using Expo. Expo is a framework that provides everything you need to get a development environment up and running quickly. Think of it like Create React App for React Native. 

Install the Expo CLI

The first thing we need to do is install the Expo CLI.


$ npm install --global expo-cli

Download Expo Go

Next, download the Expo Go app for your mobile device. This tutorial will assume you are running the app on an iPhone, but it shouldn’t matter if you are running it on Android instead. Just download the right version of Expo Go for your device.

Expo Go at the iOS App Store

Expo Go at the Android Play Store

Spin Up Your Expo App


$ expo init react-native-form-validation
$ cd react-native-form-validation

For more detail on Expo, getting started, and what else you can do with Expo, check out the Expo docs.

To check that things are working, start up the app using the CLI.


$ yarn start

This command tells Expo to start the Metro bundler, which compiles and bundles the code and serves it to the Expo Go app. Open up the Expo Go app on your phone, or scan the QR code that was printed to your console to connect to the Metro bundler and view the new app.

That’s all we need to do to get our new React Native app up and running!

Validation With Native Components

You can build a form and do custom validation with Native UI Components. Let’s make a form input that accepts and validates an email address. Create a file next to App.js called NativeComponentEmailInput.js. 

We’ll use the TextInput and TouchableHighlight components to build a simple email form.


import React, { useState } from "react";
import { TextInput, SafeAreaView, StyleSheet, Text, TouchableHighlight } from "react-native";
 
const NativeComponentEmailInput = () => {
 const [email, setEmail] = useState("");
 
 const handleSubmit = () => {
     console.log(email);
 }
 
 return (
   <SafeAreaView>
     <TextInput
         onChangeText={(text) => setEmail(text)}
         value={email}
         style={styles.emailInput}
         placeholder="Enter your email"
     />
     <TouchableHighlight onPress={handleSubmit} style={styles.button}>
        <Text style={styles.buttonText}>Submit</Text>
     </TouchableHighlight>
  </SafeAreaView>
 )
}
const styles = StyleSheet.create({
 emailInput: {
     width: 250,
     height: 50,
     borderWidth: 1,
     borderRadius: 15,
     borderColor: 'black',
     padding: 2,
 },
 button: {
     backgroundColor: 'lightgreen',
     borderRadius: 15,
     marginTop: 25,
     padding: 10,
     alignItems: 'center'
   },
   buttonText: {
     color: 'white'
 }
});
export default NativeComponentEmailInput;

Set the initial email state to an empty string using the useState hook, and pass that to the TextInput component as the value prop. Next, use onChangeText to update the state of the email to the value the user inputs. Our TouchableHighlight calls a handleSubmit function that logs our data to the console.

Remove all the boilerplate from App.js, and render the new component instead.


import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View } from 'react-native';
import NativeComponentEmailInput from './NativeComponentEmailForm';
 
export default function App() {
 return (
   <View style={styles.container}>
     <NativeComponentEmailInput/>
     <StatusBar style="auto" />
   </View>
 );
}
 
const styles = StyleSheet.create({
 container: {
   flex: 1,
   backgroundColor: '#fff',
   alignItems: 'center',
   justifyContent: 'center',
 },
});

Check out the newly rendered input in your mobile app

Add Validation Logic

Let’s use a third-party email validation API to handle email validation for us. We could also write our own validation function using a Regular Expression or some custom logic that checks the string, but honestly, relying on a service to do this for us is much easier.

We’ll use AbstractAPI’s Free Email Validation and Verification API to handle email validation.

Acquire an API Key

Go to the Email Validation API Get Started page. Click the blue “Get Started” button.

You’ll be asked to sign up if you’ve never use AbstractAPI before. If you have used the API service before, you’ll need to log in. Once you’ve done that, you’ll be taken to the API’s homepage where you’ll see options for documentation, pricing, and support.

You should also see your unique API key on this page. Each Abstract API has a unique key, so even if you’ve used AbstractAPI before, this key will be different.

Use the Key to Send a Validation Request

React Native uses the Fetch API to send and receive HTTP requests. 

Write a function called sendEmailValidationRequest to send the request to the API using Fetch.


const apiKey = 'YOUR_API_KEY';
const apiURL = 'https://emailvalidation.abstractapi.com/v1/?api_key=' + apiKey;
...
   const sendEmailValidationRequest = async (email) => {
      try {
          const response = await fetch.get(apiURL + '&email=' + email);
          const data = await response.json();
          console.log(data)
      } catch (error) {
          throw error;
      }
   }

The JSON response we’ll eventually get from the API will look something like this:


{
  "email": "eric@abstractapi.com",
  "autocorrect": "",
  "deliverability": "DELIVERABLE",
  "quality_score": "0.80",
  "is_valid_format": {
    "value": true,
    "text": "TRUE"
  },
  ...
}

There’s a lot more information in this object that has been omitted here. The part we’re interested in for now is the is_valid_format field. Let’s return the value boolean from that field so that our validation function can use it.


          const response = await fetch.get(apiURL + '&email=' + email);
          const data = await response.json();
          return data.is_valid_format.value;

Use the Response in the Submit Function

Once we have our validated response from the API, we can use it in the handleSubmit function. Add a call to the sendEmailValidationRequest function above the console.log line. Next, use the boolean response to decide whether to submit the valid email, or reject it.


  const handleSubmit = async (email) => {
      const isValid = await sendEmailValidationRequest(email);
      if (isValid) {
          console.log("SUBMITTED! ", email);
      } else {
          console.log("EMAIL WAS INVALID.");
      }
      return isValid;
  }

When the user clicks “Submit,” the handleSubmit function will first send the email input to the API for validation. If the email is valid, it will send the information to the server.

Handle Errors

We need to show the user an error message in the case that their email is not valid. Create a value for the error in state, and add a Text component to handle rendering the error message.


// state
   const [error, setError] = useState("");
...
// component
   <Text style={styles.error}>{error}</Text>
...
// stylesheet
   error: {
       color: 'red',
       alignSelf: 'center'
   }

Inside the if/else logic in our submit function, handle setting the error message if the email is invalid.


      
      if (isValid) {
          setError("");
          console.log("SUBMITTED! ", email);
      } else {
          setError("Email not valid. Please try again.")
          console.log("EMAIL WAS INVALID.");
      }

Type an invalid email address into the input and click “Submit.” When the API response returns from AbstractAPI, you should see your error message displayed.

Validation With Formik and Yup

Formik is a library that takes the headache out of building forms by providing out-of-the-box components that handle form creation, validation, etc. Yup is a schema builder that can be used to build and validate schemas. Together, they make form validation quick and easy.

Install formik and yup to your project using Yarn.


$ yarn add formik yup

Add a new file next to App.js called FormikEmailForm.js. We’ll create a new form using Formik and render that inside App.js instead to test it.

Scaffold out a basic Formik component inside your new file.


import React from "react";
import { Formik } from "formik";
import { TextInput, StyleSheet, Text, TouchableHighlight } from "react-native";
 
const FormikEmailForm = () => {
 
   return (
       <Formik
           initialValues={{ email: '' }}
           onSubmit={(values) => {console.log(values)}}
      >
          {({
              handleSubmit,
           }) => (
               <>
               <TextInput
                   name="email"
                   placeholder="Enter your email address"
                   style={styles.emailInput}
               />
                   <TouchableHighlight onPress={handleSubmit} style={styles.button}>
                       <Text style={styles.buttonText}>Submit</Text>
                  </TouchableHighlight>
               </>
 
          )}
      </Formik>
   )
}
const styles = StyleSheet.create({
 emailInput: {
     width: 250,
     height: 50,
       borderWidth: 1,
     borderRadius: 15,
       borderColor: 'black',
       padding: 2,
 },
 button: {
     backgroundColor: 'lightgreen',
     borderRadius: 15,
     marginTop: 25,
     padding: 10,
     alignItems: 'center'
   },
   buttonText: {
     color: 'white'
   },
   error: {
       color: 'red',
       alignSelf: 'center'
   }
});
export default FormikEmailForm;

You may notice that a lot of the component code is the same. Formik simply provides a wrapper for us to wrap our inputs and handles the validation and submission logic for us. You can copy a lot of the code from the last component.

Remove the previously rendered NativeComponentEmailForm from App.js and render the new Formik component instead. Check back in your mobile app to see the new component.

Add Validation Logic

Use Yup to validate your input using a custom schema. 

Create a Validation Schema

Yup enables you to create a custom schema with as many validation fields as you need for your form. It also provides out-of-the-box methods to recognize and validate inputs and return error messages if validation parameters are not met.


import * as yup from 'yup'
 
const emailValidationSchema = yup.object().shape({
 email: yup
   .string()
   .email("Please enter a valid email")
   .required('Email Address is Required'),
})

Add the Schema to the Formik Form Component

Formik provides a handy validate prop that accepts any form of validation you choose. If you’d like to send an async request to the AbstractAPI endpoint, you could do that there. You can also validate against your Yup schema using the validationSchema prop.


       <Formik
           initialValues={{ email: '' }}
           validationSchema={emailValidationSchema}
           onSubmit={(values) => {console.log(values)}}
      >

Yup automatically generates errors with error message strings if the input doesn’t match the schema. We need to pass the validation error through Formik and render the message in a text component.


       <Formik
           initialValues={{ email: '' }}
           validationSchema={emailValidationSchema}
           onSubmit={(values) => {console.log(values)}}
      >
          {({
              handleSubmit,
              errors
           }) => (
               <>
               <TextInput
                   name="email"
                   placeholder="Enter your email address"
                   style={styles.emailInput}
               />
                   <TouchableHighlight onPress={handleSubmit} style={styles.button}>
                       <Text style={styles.buttonText}>Submit</Text>
                   </TouchableHighlight>
                   <Text style={styles.error}>{errors.email}</Text>
               </>
 
          )}
      </Formik>

The easiest way to test this is to go back to your mobile app and tap “Submit” without entering anything into the text input. Since we now have a Yup validation schema with a required field and associated error message, you should see the “Email address is required” error rendered.

Validation With React Hook Form

Like Formik, React Hook Form is a library that provides out-of-the-box form components and validation. It relies on React Hooks to do this. React Hook Form allows you to register a form component to the React lifecycle and validate data using a custom validation function.

Install React Hook Form using Yarn.


$ yarn add react-hook-form

Create a new file called ReactHookEmailComponent.js next to App.js and scaffold out a basic React Hook form component. You’ll use the useForm hook to get access to a handleSubmitFunction, and a Controller, which will wrap your components.


import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextInput, StyleSheet, Text, TouchableHighlight } from "react-native";
 
const ReactHookEmailForm = () => {
 
   const { handleSubmit, control } = useForm();
 
   return (
       <>
           <Controller
               name="email"
               defaultValue=""
               control={control}
               render={({ onChange, value }) => (
                   <TextInput
                   onChange={(text) => onChange(text)}
                   value={value}
                       placeholder="Enter your email"
                       style={styles.emailInput}
                   />
               )}
           />
           <TouchableHighlight onPress={handleSubmit} style={styles.button}>
               <Text style={styles.buttonText}>Submit</Text>
           </TouchableHighlight>
       </>
 
   )
}
const styles = StyleSheet.create({
 emailInput: {
     width: 250,
     height: 50,
       borderWidth: 1,
     borderRadius: 15,
       borderColor: 'black',
       padding: 2,
 },
 button: {
     backgroundColor: 'lightgreen',
     borderRadius: 15,
     marginTop: 25,
     padding: 10,
     alignItems: 'center'
   },
   buttonText: {
     color: 'white'
   },
});
export default ReactHookEmailForm;

You’ll probably notice we copied over the same StyleSheet from the last two components. No point re-inventing the wheel.

Remove the old component from App.js and render this one instead.

Add Validation Logic

The Controller component has a useful rules prop that allows you to provide some validation parameters for the input. The rules prop accepts several parameters like minLength, maxLength, required. It also allows you to pass a RegEx pattern for validation, or pass a custom validate function.

Pass Validation Parameters to the Controller

Let’s make our email required, and also use our AbstractAPI validation function in the validate field.


   const handleEmailValidation = async (email) => {
      try {
          const response = await fetch(apiURL + '&email=' + email);
          const data = await response.json();
          return data.is_valid_format.value;
      } catch (error) {
          throw error;
      }
   }
 
...
 
         <Controller
               name="email"
               defaultValue=""
               control={control}
               rules={{required: {value: true, message: "Email is required"}, validate:       
                     (value) => handleEmailValidation(value)}}
               render={({ onChange, value }) =>
...

We can reuse the same email validation function that we used in the first example. Don’t forget to import your API key and AbstractAPI base URL.

Handle Errors

React Hook Form also provides an errors field via the useForm hook. Let’s grab it now and use it to display an error to our user.


   const { handleSubmit, control, errors } = useForm();
...
      try {
          const response = await fetch(apiURL + '&email=' + email);
          const data = await response.json();
          errors.email = ""
          return data.is_valid_format.value;
      } catch (error) {
          errors.email = "Email is invalid. Please try again."
          throw error;
      }
...
           {errors?.email && <Text style={styles.error}>{errors.email}</Text>}

Now if you try to submit an empty form or input an email address that isn’t valid, React Hook Form will catch the errors and render our error messages.

Conclusion

In this article, we explored three different methods of doing validation for a form with React Native. We also explored using the AbstractAPI Email Validation and Verification API to validate the format of email addresses. From here, adding a password field and first and last name fields would be very simple.

There is a lot more we could do with these simple inputs. For example, we aren’t handling network errors that may arise while sending the validation request to the endpoint. We also need to display a loading indicator or spinner to the user while the request is sent.

For now, however, we have a solid start on a robust, well-validated user input form for our mobile app.

FAQs

What is React Native?

React Native is a JavaScript mobile framework that enables developers to write native mobile applications using React. React Native spins up threads that interpret the JavaScript code, then creates a native bridge between the React JS code and the target platform. React Native then transfers the React JS component hierarchy to the mobile device view.

How Do I Validate Email in React Native?

You can do email validation in React Native using the Native Components TextInput component. The TextInput accepts user input, which can be stored in the component state as an email address. The TouchableHighlight component can serve as a button that runs a validation function against the email address before submitting it to the server.

There are many ways to write a custom email validation function. One way would be to match the email string against a RegEx pattern to check that it is formatted properly. You could use a third-party validation schema like Yup, or you could use a dedicated validation API like AbstractAPI’s Free Email Validation API.

How Do I Validate a Phone Number in React Native?

There are many ways to validate a phone number in React Native. The simplest way is to use a package like react-native-phone-number, which provides out-of-the-box validation methods. You could also use a dedicated phone number validation API like AbstractAPI’s Free Phone Number Validation API.

Don't reinvent the wheel, use Abstract’s suite of API tools to successfully validate emails

Get started for free
Don't reinvent the wheel, use Abstract’s suite of API tools to successfully validate emails
Get started