React Form Validation with Formik and Yup

React Form Validation with Formik and Yup

Introduction

Creating user-friendly forms is a crucial aspect of web development, but it can be challenging. Recently, I contributed to an open-source project where I built a registration form for a web application using React, Formik, and Yup. Through this experience, I gained valuable insights into creating a great user experience while implementing a robust form validation system.

In this blog post, I'll share what I learned and provide a simple guide on how to use Formik and Yup for form validation in React applications. If you are just starting, this guide will provide you with the necessary tools to create an effective form using these libraries.

Prerequisites

  • Basic understanding of React: You have a basic understanding of React (or at least have built or worked with React components). However, you can still follow along and learn if you're new to React or any of the technologies used in this article.

  • Familiarity with JavaScript: You have a solid understanding of JavaScript and its fundamental concepts, including variables, functions, and objects.

  • Familiarity with HTML and CSS: You should be familiar with HTML and CSS to create and style the form.

A code editor (VS Code is recommended) and, of course, a web browser

What are Formik and Yup?

Formik is a popular library for building forms in React. It simplifies form management by handling form state, validation, and submission, and provides a clean API for rendering and updating form fields. Yup is a schema validation library that works well with Formik, allowing us to define the validation rules for our form fields.

Part 1: Setting Up the Registration Form

To start with, we need to set up the basic structure of our registration form. We'll create a new component called RegistrationForm, which will contain all the form fields and validation logic. The first step is to install Formik and Yup by running the following command in your terminal:

npm install formik yup

Next, let's import Formik and Yup into our component:

import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

Let's create our RegistrationForm component. We will use the Formik component to wrap the Form component, both of which have been imported from formikand it takes three props:

  • initialValues: an object containing the initial values of our form fields

  • validation schema: a Yup schema that defines the validation rules for our form fields

  • onSubmit: a function that's called when the form is submitted.

    And then we have theisSubmitting boolean property destructed from the Formik component's render props, and it is set to true during form submission or false when the process is completed. We will use this property to disable the submit button once we trigger the form submission process. You can also use it to display a loading spinner.

    Using this property gives a great user experience as it lets the user know when a submission process is in progress.

const RegistrationForm = () => {
  return (
    <Formik
      initialValues={{
        firstName: '',
        lastName: '',
        email: '',
        eventType: '',
        password: '',
        confirmPassword: ''
      }}
      validationSchema={/* add Yup validation schema here */}
      onSubmit={/* add form submission logic here */}
    >
      {({ isSubmitting }) => (
        <Form>
          {/* add form fields here */}
          <button type="submit" disabled={isSubmitting}>
            Sign Up
          </button>
        </Form>
      )}
    </Formik>
  );
};

Part 2: Adding Form Fields

Now that we have our basic component, let's add the form fields. We'll use Formik'sField component to create each form field. Each form field takes a name prop that matches the corresponding key in our initialValues object.

// Renders an HTML <input> by default
<Field name="firstName" placeholder="First Name" />
<Field name="lastName" placeholder="Last Name" />
<Field name="email" placeholder="Email" />
// Renders an HTML <select>
 <Field name="eventType" as="select">
   <option value="virtual">Virtual</option>
   <option value="inPerson">In-person</option>
 </Field>
<Field name="password" type="password" placeholder="Password" />
<Field name="confirmPassword" type="password" placeholder="Confirm Password" />

Then, let's use theErrorMessage component, which also takes a name prop, and/or component prop (optional) from Formik, to display validation errors next to each form field.

<Field name="firstName" placeholder="First Name" />
<ErrorMessage name="firstName" component="div" />

Part 3: Adding Form Validation

After setting up our form fields, we can add validation to our form. We'll use Yup to define the validation schema for our form. In this case, we want to ensure that all fields are required and that the email and password fields meet specific criteria. Here's the validation schema for our fields: You can check out the Yup docs for more details on defining your schema.

const validationSchema = Yup.object().shape({
  firstName: Yup.string().required('First name is required'),
  lastName: Yup.string().required('Last name is required'),
  email: Yup.string().email('Invalid email').required('Email is required'),
  eventType: Yup.string().required('Event type is required'),
  password: Yup.string()
    .required('Password is required')
    .min(8, 'Password must be at least 8 characters long'),
  confirmPassword: Yup.string()
    .oneOf([Yup.ref('password'), null], 'Passwords must match')
    .required('Confirm Password is required')
});

We'll then pass this validation schema to the Formik component as a prop.

<Formik
  initialValues={{
    firstName: '',
    lastName: '',
    email: '',
    eventType: '',
    password: '',
    confirmPassword: ''
  }}
  validationSchema={validationSchema}
  onSubmit={/* add form submission logic here */}
>

Part 4: Handling Form Submission

We have our form fields and validation set up; now we need to handle the form submission. We'll use theonSubmit prop in the Formik component to define what happens when the user submits the form.

  • setSubmittingWhat this function does is set theisSubmitting property to either true or false, depending on the boolean it is called with. If it is called with the boolean true, the isSubmitting sets totrue, and if it is called with false, isSubmitting sets tofalse.

  • resetFormIt is a function provided by Formik that resets the form to its original initial values. By using theresetForm method, we can easily reset the form to its initial state after submission, making it easier for the user to fill out the form multiple times without having to clear the fields manually.

const handleSubmit = (values, { setSubmitting, resetForm }) => {
  setTimeout(() => {
    alert(JSON.stringify(values, null, 2));
    resetForm();
    setSubmitting(false);
  }, 400);
};

We'll pass this function to the onSubmit prop in our RegistrationForm component:

<Formik
  initialValues={{
    firstName: '',
    lastName: '',
    email: '',
    eventType: '',
    password: '',
    confirmPassword: ''
  }}
  validationSchema={validationSchema}
  onSubmit={handleSubmit}
>

Part 5: Putting It All Together

With all the pieces in place, let's see our form component in action:

const RegistrationForm = () => {
  const validationSchema = Yup.object().shape({
    firstName: Yup.string().required('First name is required'),
    lastName: Yup.string().required('Last name is required'),
    email: Yup.string().email('Invalid email').required('Email is required'),
    eventType: Yup.string().required('Event type is required'),
    password: Yup.string()
      .required('Password is required')
      .min(8, 'Password must be at least 8 characters long'),
    confirmPassword: Yup.string()
      .oneOf([Yup.ref('password'), null], 'Passwords must match')
      .required('Confirm Password is required')
  });

  const handleSubmit = (values, { setSubmitting, resetForm }) => {
    setTimeout(() => {
      alert(JSON.stringify(values, null, 2));
      resetForm();
      setSubmitting(false);
    }, 400);
  };
  return (
    <Formik
      initialValues={{
        firstName: '',
        lastName: '',
        email: '',
        eventType: '',
        password: '',
        confirmPassword: ''
      }}
      validationSchema={validationSchema}
      onSubmit={handleSubmit}
    >
      {({ isSubmitting }) => (
        <Form>
          <Field name="firstName" placeholder="First Name" />
          <ErrorMessage name="firstName" />
          <Field name="lastName" placeholder="Last Name" />
          <ErrorMessage name="lastName" />
          <Field name="email" placeholder="Email" />
          <ErrorMessage name="email" />
          <Field name="eventType" as="select">
             <option value="virtual">Virtual</option>
             <option value="inPerson">In-person</option>
          </Field>
          <ErrorMessage name="eventType" />
          <Field name="password" type="password" placeholder="Password" />
          <ErrorMessage name="password" />
          <Field name="confirmPassword" type="password" placeholder="Confirm              Password" />
          <ErrorMessage name="confirmPassword" />
          <button type="submit" disabled={isSubmitting}>
            Sign Up
          </button>
        </Form>
      )}
    </Formik>
  );
};

Conclusion

Great! You have just learned how to add validations to your form using Yup, set up the form fields, and handle the form submission with Formik. This blog post is mostly focused on form validation and submission, so we didn't cover the handleChange method that is usually called with the onChange prop in your form fields. With Formik and Yup, building robust and user-friendly forms in React is a breeze. I hope this tutorial has helped get started with building your own validated forms in React!

Kindly drop any suggestions or corrections in the comment section.

References

Formik

Yup