Form Validation a breeze with Yup and React Hook form
Tags: javascript, react, webdev
Published: 2022-08-24 09:18:00

Hello everyone, today I'll be guiding us on how to add form validation to our React application using Yup and react hook form.

Video version
[Video version youtube](https://youtu.be/chYXh7TG9ZE)

Final Demo
![Form validation in react](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z6q8qxavw7a98km9sm4q.gif)
 
 

Getting started, I've generated a new react project and setup tailwind css.
Incase you want to add tailwind css to your react project please follow this guide [tailwindcss-react](https://tailwindcss.com/docs/guides/create-react-app)

This is what I currently have:
App.js
```
function App() {
  return <div className="w-screen h-screen bg-gradient-to-r from-blue-900 to-purple-900 grid place-content-center">

  </div>;
}

export default App;

```

Next let's create a components folder that will hold our Form component

src/components/Form/Form.jsx

At this point we're going to create our form component and have our various form inputs

```
const textInputClassName =
  "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500";

const Form = () => {
  return (
    <div className="md:w-[500px] shadow-sm shadow-white bg-white w-[320px] mx-auto px-7 py-4 rounded-xl">
      <form className="w-full">
        <div className="mb-6">
          <label
            htmlFor="email"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your email
          </label>
          <input
            type="email"
            id="email"
            className={textInputClassName}
            placeholder="test@test.com"
          />
        </div>
        <div className="mb-6">
          <label
            htmlFor="password"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your password
          </label>
          <input type="password" id="password" className={textInputClassName} />
        </div>
        <div className="mb-6">
          <label
            htmlFor="confirmPassword"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Confirm Password
          </label>
          <input
            type="password"
            id="confirmPassword"
            className={textInputClassName}
          />
        </div>
        <div className="mb-6">
          <label
            htmlFor="accountType"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400"
          >
            Select an option
          </label>
          <select
            id="accountType"
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
          >
            <option value="">Account Type</option>
            <option value="personal">Personal</option>
            <option value="commercial">Commercial</option>
          </select>
        </div>
        <div className="flex justify-between mb-6">
          <div className="flex">
            <div className="flex items-center h-5">
              <input
                id="remember"
                type="checkbox"
                value=""
                className="w-4 h-4 bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800"
              />
            </div>
            <label
              htmlFor="remember"
              className="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300"
            >
              Remember me
            </label>
          </div>

          <div>
            <label
              htmlFor="default-toggle"
              className="inline-flex relative items-center cursor-pointer"
            >
              <input
                type="checkbox"
                value=""
                id="default-toggle"
                className="sr-only peer"
              />
              <div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
              <span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
                Toggle me
              </span>
            </label>
          </div>
        </div>

        <button
          type="submit"
          className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
        >
          Submit
        </button>
      </form>
    </div>
  );
};

export default Form;

```

Now we're done with our Form component JSX, let's go on and add our form to App.js

```
import Form from "./components/Form/Form";

function App() {
  return (
    <div className="w-screen h-screen bg-gradient-to-r from-blue-900 to-purple-900 grid place-content-center">
      <Form />
    </div>
  );
}

export default App;

```
Our App.js now looks like this which gives us this result


![css-form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i01ly30ion6bwewav78k.png)

---
Now we've our form design, let's proceed to adding validation. We need to install the following packages
---
`npm install -D yup @hookform/resolvers react-hook-form`
or incase you use yarn
`yarn add -D yup @hookform/resolvers react-hook-form`

Yup is going to be our schema builder for value parsing and validation,
React-hook-form is going to help us validate our form input,
@hookform/resolvers is used to integrate yup and react-hook-form nicely. 

Let's import the packages we just installed in our Form component

**/components/Form/Form.jsx**
```
import { useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
```
Before we start building our ValidationSchema, we need to add a **name attribute** to our html form, as this is important for yup and react-hook-form to keep track of our different inputs.

```
   <form className="w-full">
        <div className="mb-6">
          <label
            htmlFor="email"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your email
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className={textInputClassName}
            placeholder="test@test.com"
          />
        </div>
        <div className="mb-6">
          <label
            htmlFor="password"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your password
          </label>
          <input type="password" id="password" className={textInputClassName} />
        </div>
        <div className="mb-6">
          <label
            htmlFor="confirmPassword"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Confirm Password
          </label>
          <input
            name="password"
            type="password"
            id="confirmPassword"
            className={textInputClassName}
          />
        </div>
        <div className="mb-6">
          <label
            htmlFor="accountType"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400"
          >
            Select an option
          </label>
          <select
            name="accountType"
            id="accountType"
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
          >
            <option value="">Account Type</option>
            <option value="personal">Personal</option>
            <option value="commercial">Commercial</option>
          </select>
        </div>
        <div className="flex justify-between mb-6">
          <div className="flex">
            <div className="flex items-center h-5">
              <input
                id="remember"
                name="remember"
                type="checkbox"
                value=""
                className="w-4 h-4 bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800"
              />
            </div>
            <label
              htmlFor="remember"
              className="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300"
            >
              Remember me
            </label>
          </div>

          <div>
            <label
              htmlFor="toggle"
              className="inline-flex relative items-center cursor-pointer"
            >
              <input
                type="checkbox"
                name="toggle"
                value=""
                id="toggle"
                className="sr-only peer"
              />
              <div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
              <span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
                Accept
              </span>
            </label>
          </div>
        </div>

        <button
          type="submit"
          className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
        >
          Submit
        </button>
      </form>
```

Let's build our validation schema, for this I'll create a new schema folder and inside a formSchema.js file.

let's write our formSchema, like this

```
import * as yup from "yup";

export const registerSchema = yup.object().shape({
  email: yup
    .string("email should be a string")
    .email("please provide a valid email address")
    .required("email address is required"),
});
```
The email key should match the name attribute in your jsx.

In our Form.js
`import { registerSchema } from "../../schema/formSchema";`

```
// Saving space

const Form = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: yupResolver(registerSchema),
  });

// Saving space
}
```
register will be used to register our inputs with react-hook-form,
handleSubmit should be added to our form onSubmit and when we submit our form, will help use validate our form,
formState helps us keep track of our form state, in this case error state.

let's add this to our email input, please take note of `{...register("email")}` and the error jsx

```
<label
            htmlFor="email"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your email
          </label>
          <input
            {...register("email")}
            type="email"
            name="email"
            id="email"
            className={textInputClassName}
            placeholder="test@test.com"
          />
          {errors.email ? (
            <span className="text-red-900">{errors.email.message}</span>
          ) : (
            <></>
          )}
```

on our form submit handler, let's add this

```
<form onSubmit={handleSubmit(formSubmitHandler)} className="w-full">
// saving space
</from
```

You'll notice we've passed formSubmitHandler which is our custom function that will be passed the form data automatically if validation passes

```
  const formSubmitHandler = (data) => {
    console.log(data);
  };
```
With this our form validation is working already and we should have a result like this
![Email validation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmhh65yks81vvecexuoc.gif)
 
validating password and confirm password

Let's add the following to our schema file

```
export const registerSchema = yup.object().shape({
  email: yup
    .string("email should be a string")
    .email("please provide a valid email address")
    .required("email address is required"),
  password: yup
    .string("password should be a string")
    .min(5, "password should have a minimum length of 5")
    .max(12, "password should have a maximum length of 12")
    .required("password is required"),
  confirmPassword: yup
    .string("password should be a string")
    .oneOf([yup.ref("password")])
    .required("confirm password is required"),
});

```

Back to our Form.js, let's update our password and confirm password to this

```
<div className="mb-6">
          <label
            htmlFor="password"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Your password
          </label>
          <input
            {...register("password")}
            type="password"
            name="password"
            id="password"
            className={textInputClassName}
          />
          {errors.password ? (
            <span className="text-red-900">{errors.password.message}</span>
          ) : (
            <></>
          )}
        </div>
        <div className="mb-6">
          <label
            htmlFor="confirmPassword"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            Confirm Password
          </label>
          <input
            {...register("confirmPassword")}
            name="confirmPassword"
            type="password"
            id="confirmPassword"
            className={textInputClassName}
          />
          {errors.confirmPassword ? (
            <span className="text-red-900">{errors.confirmPassword.message}</span>
          ) : (
            <></>
          )}
        </div>
```

This gives us this result

![Password and confirm password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nul28rqglx8q2eqrtnhc.gif)
 
Validating Select

Let's update our schema file to the following

```
import * as yup from "yup";

export const registerSchema = yup.object().shape({
  email: yup
    .string("email should be a string")
    .email("please provide a valid email address")
    .required("email address is required"),
  password: yup
    .string("password should be a string")
    .min(5, "password should have a minimum length of 5")
    .max(12, "password should have a maximum length of 12")
    .required("password is required"),
  confirmPassword: yup
    .string("password should be a string")
    .oneOf([yup.ref("password")])
    .required("confirm password is required"),
  accountType: yup
    .string("account type should be a string")
    .oneOf(["personal", "commercial"])
    .required("account type is required"),
});

```

Now let's also update our select jsx

```
<div className="mb-6">
          <label
            htmlFor="accountType"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400"
          >
            Select an option
          </label>
          <select
            {...register("accountType")}
            name="accountType"
            id="accountType"
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
          >
            <option value="">Account Type</option>
            <option value="personal">Personal</option>
            <option value="commercial">Commercial</option>
          </select>{" "}
          {errors.accountType ? (
            <span className="text-red-900">{errors.accountType.message}</span>
          ) : (
            <></>
          )}
        </div>
```

Now we've this

![Select validation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lv19urbf3qm8c9qr406.gif)
 
Lastly, let's validate our toggle and checkbox

We start by updating our schema file

```
import * as yup from "yup";

export const registerSchema = yup.object().shape({
  email: yup
    .string("email should be a string")
    .email("please provide a valid email address")
    .required("email address is required"),
  password: yup
    .string("password should be a string")
    .min(5, "password should have a minimum length of 5")
    .max(12, "password should have a maximum length of 12")
    .required("password is required"),
  confirmPassword: yup
    .string("password should be a string")
    .oneOf([yup.ref("password")])
    .required("confirm password is required"),
  accountType: yup
    .string("account type should be a string")
    .oneOf(["personal", "commercial"])
    .required("account type is required"),
  remember: yup.boolean().oneOf([true], "Please tick checkbox"),
  toggle: yup.boolean().oneOf([true], "Please toggle accept"),
});

```

Then let's update our from checkbox and toggle jsx

```
<div className="flex justify-between mb-6">
          <div>
            <div className="flex">
              <div className="flex items-center h-5">
                <input
                  {...register("remember")}
                  id="remember"
                  name="remember"
                  type="checkbox"
                  value=""
                  className="w-4 h-4 bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800"
                />
              </div>
              <label
                htmlFor="remember"
                className="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300"
              >
                Remember me
              </label>
            </div>
            {errors.remember ? (
              <span className="text-red-900">{errors.remember.message}</span>
            ) : (
              <></>
            )}
          </div>

          <div>
            <div>
              <label
                htmlFor="toggle"
                className="inline-flex relative items-center cursor-pointer"
              >
                <input
                  {...register("toggle")}
                  type="checkbox"
                  name="toggle"
                  value=""
                  id="toggle"
                  className="sr-only peer"
                />
                <div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
                <span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
                  Accept
                </span>
              </label>
            </div>
            {errors.toggle ? (
              <span className="text-red-900">{errors.toggle.message}</span>
            ) : (
              <></>
            )}
          </div>
        </div>
```

Whooaa with this, we're done with this result
![validating checkbox and toggle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oy0ambn9s2qxu0tj3ap4.gif)
 
Thank you for following, incase you need the final code, here's the github repo

[github repo link](https://github.com/laribright/yup-react-hook-from.git)

Please do connect with me
[linkedIn](https://www.linkedin.com/in/laribright/)
[youtube](https://www.youtube.com/channel/UCTvF1UElM6k1LrLV7u4prow)
[Udemy](https://www.udemy.com/user/alaribe-bright/)