React Form Validation example with Hooks, Formik and Yup

In this tutorial, I will show you how to implement React Form Validation and Submit example using Formik, Yup and Bootstrap 4.

More Practice:
React Custom Hook
React Hooks: CRUD example with Rest API
React Hooks File Upload example with Axios & Progress Bar
React Hooks: JWT Authentication (without Redux) example
React Hooks + Redux: JWT Authentication example

Serverless:
React Hooks + Firebase Realtime Database: CRUD App
React Hooks + Firestore example: CRUD app

Using React Hook Form instead:
React Form Validation with Hooks, Bootstrap | react-hook-form 7


Overview of React Hooks Form Validation example

We will implement validation for a React Form using Formik and Bootstrap 4 with React Hooks. The form has:

  • Full Name: required
  • Username: required, from 6 to 20 characters
  • Email: required, email format
  • Password: required, from 6 to 40 characters
  • Confirm Password: required, same as Password
  • Accept Terms Checkbox: required

react-hooks-form-validation-example-formik-yup

Some fields could be wrong:

react-hooks-form-validation-example-formik-yup-submit-error

Successful Submission will look like this:

react-hooks-form-validation-example-formik-yup-submit

Technology

We’re gonna use following modules:

  • react 17/16
  • bootstrap 4
  • formik 2
  • yup

Setup Project

First we need to install necessary modules.
Open your project root folder, run the command:

npm install formik yup

# Or:
yarn add formik yup

Open package.json, the dependencies will look like this:

{
  "name": "react-form-validation-example",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    ...
    "formik": "^2.2.9",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "yup": "^0.32.9"
  },
  ...
}

Import Bootstrap

Open public/index.html and add following line to <head> tag:

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <link href="//netdna.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
    ...
    <title>React Hooks Form Validation example</title>
  </head>
  <body>
    ...
    <div id="root"></div>
  </body>
</html>

Or you can run command: npm install bootstrap.

Then open src/App.js and modify the code inside it as following-

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";

function App() {
  return (
    ...
  );
}

export default App;

React Hooks Form Validation example with Formik

The app component contains Form Validation example built with Formik and Yup library.

Formik, together with Yup, help handling forms conveniently in React. With Yup, we can create schema for validation abstractly instead of creating custom validation for each input field.

You need to notice following important Formik attributes:

  • initialValues
  • validationSchema
  • onSubmit

Open src/App.js, we’re gonna import necessary library first:

import React from 'react';
import { useFormik } from "formik";
import * as Yup from 'yup';

Next we use Yup schema validation library for Form validation rules:

function App() {
  const validationSchema = Yup.object().shape({
    fullname: Yup.string().required("Fullname is required"),
    username: Yup.string()
      .required("Username is required")
      .min(6, "Username must be at least 6 characters")
      .max(20, "Username must not exceed 20 characters"),
    email: Yup.string().required("Email is required").email("Email is invalid"),
    password: Yup.string()
      .required("Password is required")
      .min(6, "Password must be at least 6 characters")
      .max(40, "Password must not exceed 40 characters"),
    confirmPassword: Yup.string()
      .required("Confirm Password is required")
      .oneOf([Yup.ref("password"), null], "Confirm Password does not match"),
    acceptTerms: Yup.bool().oneOf([true], "Accept Terms is required"),
  });

  ...
}

Next, instead of managing our form’s values with custom event handlers for every single input, we can just use useFormik() which is a custom React hook. It will return all Formik state and helpers directly.

function App() {
  ...

  const formik = useFormik({
    initialValues: {
      fullname: "",
      username: "",
      email: "",
      password: "",
      confirmPassword: "",
      acceptTerms: false,
    },
    validationSchema,
    // validateOnChange: false,
    // validateOnBlur: false,
    onSubmit: (data) => {
      console.log(JSON.stringify(data, null, 2));
    },
  });
  ...
}

initialValues: object for initial values of the form fields. Each key of the object must correspond with the name of the Formik input field.

validationSchema: function for handling validation. It receives form data values and validates each property based on the rules defined. Each key of the object must correspond with the name of the Formik input field.

onSubmit: function for handling submission. It receives callback function that will run when the validation has passed without any error.

You can also trigger validation only on form submit by setting validateOnChange and validateOnBlur to false.

React Hooks Form Validation with Formik template

Now we create the form with input fields and validation messages.

function App() {
  ...

  return (
    <div className="register-form">
      <form onSubmit={formik.handleSubmit}>
        <div className="form-group">
          <label>Full Name</label>
          <input
            name="fullname"
            type="text"
            className={
              'form-control' +
              (formik.errors.fullname && formik.touched.fullname
                ? ' is-invalid'
                : '')
            }
            onChange={formik.handleChange}
            value={formik.values.fullname}
          />
          <div className="invalid-feedback">
            {formik.errors.fullname && formik.touched.fullname
              ? formik.errors.fullname
              : null}
          </div>
        </div>

        <div className="form-group">
          <label htmlFor="username"> Username </label>
          <input
            name="username"
            type="text"
            className={
              'form-control' +
              (formik.errors.username && formik.touched.username
                ? ' is-invalid'
                : '')
            }
            onChange={formik.handleChange}
            value={formik.values.username}
          />
          <div className="invalid-feedback">
            {formik.errors.username && formik.touched.username
              ? formik.errors.username
              : null}
          </div>
        </div>

        <div className="form-group">
          <label htmlFor="email"> Email </label>
          <input
            name="email"
            type="email"
            className={
              'form-control' +
              (formik.errors.email && formik.touched.email ? ' is-invalid' : '')
            }
            onChange={formik.handleChange}
            value={formik.values.email}
          />
          <div className="invalid-feedback">
            {formik.errors.email && formik.touched.email
              ? formik.errors.email
              : null}
          </div>
        </div>

        <div className="form-group">
          <label htmlFor="password"> Password </label>
          <input
            name="password"
            type="password"
            className={
              'form-control' +
              (formik.errors.password && formik.touched.password
                ? ' is-invalid'
                : '')
            }
            onChange={formik.handleChange}
            value={formik.values.password}
          />
          <div className="invalid-feedback">
            {formik.errors.password && formik.touched.password
              ? formik.errors.password
              : null}
          </div>
        </div>

        <div className="form-group">
          <label htmlFor="confirmPassword"> Confirm Password </label>
          <input
            name="confirmPassword"
            type="password"
            className={
              'form-control' +
              (formik.errors.confirmPassword && formik.touched.confirmPassword
                ? ' is-invalid'
                : '')
            }
            onChange={formik.handleChange}
            value={formik.values.confirmPassword}
          />
          <div className="invalid-feedback">
            {formik.errors.confirmPassword && formik.touched.confirmPassword
              ? formik.errors.confirmPassword
              : null}
          </div>
        </div>

        <div className="form-group form-check">
          <input
            name="acceptTerms"
            type="checkbox"
            className={
              'form-check-input' +
              (formik.errors.acceptTerms && formik.touched.acceptTerms
                ? ' is-invalid'
                : '')
            }
            onChange={formik.handleChange}
            value={formik.values.acceptTerms}
          />
          <label htmlFor="acceptTerms" className="form-check-label">
            I have read and agree to the Terms
          </label>
          <div className="invalid-feedback">
            {formik.errors.acceptTerms && formik.touched.acceptTerms
              ? formik.errors.acceptTerms
              : null}
          </div>
        </div>

        <div className="form-group">
          <button type="submit" className="btn btn-primary">
            Register
          </button>
          <button
            type="button"
            className="btn btn-warning float-right"
            onClick={formik.handleReset}
          >
            Reset
          </button>
        </div>
      </form>
    </div>
  );
}

export default App;

handleSubmit: submission handler
handleChange: change handler to pass to each <input>
values: form’s current values
handleReset: reset handler or using <button type="reset">

You can see that we use the name attribute to match up with Formik state.

Remember that <Field>, <ErrorMessage>… will NOT work with useFormik() because they require React Context.

Run React Form Validation example

You can run our App with command: yarn start or npm run start.
If the process is successful, open Browser with Url: http://localhost:3000/ and check it.

Or run on Stackblitz:

Conclusion

Today we’ve built a React Form Validation example successfully using React Hooks, Formik, Yup & Bootstrap 4.

You can also implement this Form Validation in following posts:
React Hooks: CRUD example with Rest API
React Hooks: JWT Authentication (without Redux) example
React Hooks + Redux: JWT Authentication example

Further Reading

React Custom Hook
React Hooks File Upload example with Axios & Progress Bar
React Pagination using Hooks example

Serverless with Firebase:
React Hooks + Firebase Realtime Database: CRUD App
React Hooks + Firestore example: CRUD app

Fullstack:
React + Spring Boot + MySQL: CRUD example
React + Spring Boot + PostgreSQL: CRUD example
React + Spring Boot + MongoDB: CRUD example
React + Node.js + Express + MySQL: CRUD example
React + Node.js + Express + PostgreSQL example
React Redux + Node.js + Express + MySQL: CRUD example
React + Node.js + Express + MongoDB example
React + Django + Rest Framework example

2 thoughts to “React Form Validation example with Hooks, Formik and Yup”

Comments are closed to reduce spam. If you have any question, please send me an email.