Manage Forms in React With Formik - Form Validation

Form validation is a crucial part of any application form,  we need to put validation in such a way that the user doesn't fill in the wrong details. We also need to show the appropriate message when a user enters any invalid details.
 
In the previous article, we have seen how to manage react forms with Formik. In this article, we will go further with form validation, we will see how to setup form validation schema, and show the appropriate message. 
 
 
 
So let's get started.
 

Form Validation with Formik

 
" Formik is designed to manage forms with complex validation with ease. Formik supports synchronous and asynchronous form-level and field-level validation - Formik Docs".
 
Formik supports the schema-based form validation with Yup. Yup is a JavaScript schema builder for value parsing and validation.
 
We will continue with our previous example at stackblitz.
 
Install Yup
  1. npm install --save yup  

Create Validation Schema

 
We will import the yup and create the validation schema as below,
  1. const validationSchema = yup.object().shape({  
  2.   firstName: yup  
  3.     .string()  
  4.     .required()  
  5.     .min(3),  
  6.   lastName: yup.string().required(),  
  7.   emailId: yup  
  8.     .string()  
  9.     .required()  
  10.     .email(),  
  11.   mobileNumber: yup.number()  
  12. });   
Here I have not used any validation message when there is an error, So yup will automatically generate a validation message based on the key.

For example,
  • firstName is a required field 
  • firstName must be at least 3 characters etc. 
This is not user friendly, so we will write different message instead of default one as below,
  1. const validationSchema = yup.object().shape({  
  2.   firstName: yup  
  3.     .string()  
  4.     .required('First name is required.')  
  5.     .min(3, 'Minimum 3 characters required'),  
  6.   lastName: yup.string().required('Last name is required'),  
  7.   emailId: yup  
  8.     .string()  
  9.     .required('Email ID is required')  
  10.     .email('Enter valid email id'),  
  11.   mobileNumber: yup.number()  
  12. });  

Use Validation Schema 


Now we will set this validation schema with useFormik() hook as shown below. Formik uses this validation schema to validate the input controls when the form state is changed. 
  1. const formik = useFormik({  
  2.   initialValues: {  
  3.     firstName: '',  
  4.     lastName: '',  
  5.     emailId: '',  
  6.     mobileNumber: undefined,  
  7.     gender: '',  
  8.     address: ''  
  9.   },  
  10.   onSubmit: values => {  
  11.     alert(  
  12.       'Registration Form Submitted \n ' + JSON.stringify(values, null, 2)  
  13.     );  
  14.     formik.resetForm();  
  15.   },  
  16.   validationSchema: validationSchema  
  17. });  
As you can see in line number 16, we have set the validation schema.
 

Formik State For Error Handling


Formik object provides various state which we can use to handle the error.
  • isValid - true when all validation is fulfilled else false.
  • dirty - true when the change in any form control value.
  • errors - gives the errors of each form control.
    1. {  
    2.   "firstName""First name is required.",  
    3.   "lastName""Last name is required",  
    4.   "emailId""Email ID is required"  
    5. }  
    We will use this property to show the error message for each control.

  • touched - touched state of all the form controls.
    1. {  
    2.   "firstName"true,  
    3.   "lastName"true,  
    4.   "emailId"true  
    5. }  

Show Error Message 


Now we will use the above states to show error messages for each form control. We will create one function which will take field name as input and render an error message if control is touched and have an error.
  1. const renderErrorMessage = field => {  
  2.   return (  
  3.     formik.touched[field] && (  
  4.       <div class="text-error">{formik.errors[field]}</div>  
  5.     )  
  6.   );  
  7. };  
We will use this function in each form control as shown below,
  1. <div>  
  2.       <input type="text" {...formik.getFieldProps('firstName')} />  
  3.         { renderErrorMessage('firstName') }  
  4. </div>  
We have also added CSS in App.css for .text-error.
 
Final Code 
  1. // App.js / App.jsx  
  2.   
  3. import React from 'react';  
  4. import './style.css';  
  5. import { useFormik } from 'formik';  
  6. import * as yup from 'yup';  
  7.   
  8. const validationSchema = yup.object().shape({  
  9.   firstName: yup  
  10.     .string()  
  11.     .required('First name is required.')  
  12.     .min(3, 'Minimum 3 characters required'),  
  13.   lastName: yup.string().required('Last name is required'),  
  14.   emailId: yup  
  15.     .string()  
  16.     .required('Email ID is required')  
  17.     .email('Enter valid email id'),  
  18.   mobileNumber: yup.number()  
  19. });  
  20.   
  21. export default function App() {  
  22.   const formik = useFormik({  
  23.     initialValues: {  
  24.       firstName: '',  
  25.       lastName: '',  
  26.       emailId: '',  
  27.       mobileNumber: undefined,  
  28.       gender: '',  
  29.       address: ''  
  30.     },  
  31.     onSubmit: values => {  
  32.       alert(  
  33.         'Registration Form Submitted \n ' + JSON.stringify(values, null, 2)  
  34.       );  
  35.       formik.resetForm();  
  36.     },  
  37.     validationSchema: validationSchema  
  38.   });  
  39.   
  40.   const renderErrorMessage = field => {  
  41.     return (  
  42.       formik.touched[field] && (  
  43.         <div class="text-error">{formik.errors[field]}</div>  
  44.       )  
  45.     );  
  46.   };  
  47.   
  48.   return (  
  49.     <div class="root">  
  50.       <div class="form">  
  51.         <h1> Registration </h1>  
  52.         <form onSubmit={formik.handleSubmit}>  
  53.           <div class="form-group">  
  54.             <label> First Name </label>  
  55.             <div>  
  56.               <input type="text" {...formik.getFieldProps('firstName')} />  
  57.               {renderErrorMessage('firstName')}  
  58.             </div>  
  59.           </div>  
  60.           <div class="form-group">  
  61.             <label> Last Name </label>  
  62.             <div>  
  63.               <input type="text" {...formik.getFieldProps('lastName')} />  
  64.               {renderErrorMessage('lastName')}  
  65.             </div>  
  66.           </div>  
  67.           <div class="form-group">  
  68.             <label> Email Id </label>  
  69.             <div>  
  70.               <input type="text" {...formik.getFieldProps('emailId')} />  
  71.               {renderErrorMessage('emailId')}  
  72.             </div>  
  73.           </div>  
  74.           <div class="form-group">  
  75.             <label> Mobile Number </label>  
  76.             <input type="text" {...formik.getFieldProps('mobileNumber')} />  
  77.           </div>  
  78.           <div class="form-group">  
  79.             <label> Gender </label>  
  80.             <select {...formik.getFieldProps('gender')}>  
  81.               <option value="">Select</option>  
  82.               <option value="male">Male</option>  
  83.               <option value="female">Female</option>  
  84.             </select>  
  85.           </div>  
  86.           <div class="form-group">  
  87.             <label> Address </label>  
  88.             <textarea type="text" {...formik.getFieldProps('address')} />  
  89.           </div>  
  90.           <div>  
  91.             <button type="submit" class="btn-primary">  
  92.               Submit  
  93.             </button>  
  94.             <button  
  95.               type="reset"  
  96.               class="btn-secondary"  
  97.               onClick={formik.resetForm}  
  98.             >  
  99.               Reset  
  100.             </button>  
  101.           </div>  
  102.         </form>  
  103.       </div>  
  104.       <div class="form-state">  
  105.         <h4>Form State</h4>  
  106.         <h5>Is Dirty: {JSON.stringify(formik.dirty)}</h5>  
  107.         <h5>Valid: {JSON.stringify(formik.isValid)}</h5>  
  108.         <h5>values:</h5>  
  109.         <code>  
  110.           <pre>{JSON.stringify(formik.values, null, 2)}</pre>  
  111.         </code>  
  112.         <h5>Errors:</h5>  
  113.         <code>  
  114.           <pre>{JSON.stringify(formik.errors, null, 2)}</pre>  
  115.         </code>  
  116.         <h5>Touched:</h5>  
  117.         <code>  
  118.           <pre>{JSON.stringify(formik.touched, null, 2)}</pre>  
  119.         </code>  
  120.       </div>  
  121.     </div>  
  122.   );  
  123. }  

Final Output

 
Form Validation with Formik in React
 

Checkout Live Application

 
Great !!! We are done with the form validation implementation.


Summary


In this article, we have seen how to do form validation with Formik. We have seen validation schema setup, Formik state values which we have used for showing errors and rendering the error message.
 
I hope you like this article, give your feedback and suggestion in the comment section below.