DEV Community

Cover image for React form validation with React Hook Form and Yup
Francisco Mendes
Francisco Mendes

Posted on

React form validation with React Hook Form and Yup

Validating user input on forms prior to submission, in my opinion, is one of the most important and fundamental things about a website these days.

Thank god we have several options to validate them, in the React ecosystem there are lots of libraries. However many of these libraries either end up having a huge boilerplate, which is sometimes scary, even when implementing in a form with few fields. Or they decrease application performance.

Keeping these points in mind, I always end up looking for a solution that is simple, with little boilerplate and that has a great performance.

Apart from that, another thing I'm looking for is a form validation library that lets you use a library to validate schemas, such as Joi, Yup, etc. This way I can reuse the schema code in the frontend and backend.

It's exactly for all these reasons that I love working with React Hook Form.

Let's code

First we will add the following dependencies to our React application:

npm install react-hook-form @hookform/resolvers yup
Enter fullscreen mode Exit fullscreen mode

Now let's pretend this is your form:

import React from "react";

const App = () => {
  return (
    <form>
      <h2>Lets sign you in.</h2>
      <br />

      <input placeholder="email" type="email" required />
      <br />

      <input
        placeholder="password"
        type="password"
        required
      />
      <br />

      <button type="submit">Sign in</button>
    </form>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Now let's import React Hook Form into our project:

import React from "react";
import { useForm } from "react-hook-form";
// Hidden for simplicity
Enter fullscreen mode Exit fullscreen mode

Then let's get the following things from the useForm() hook:

const App = () => {
  const { register, handleSubmit, formState: { errors }, reset } = useForm();
  return (
    // Hidden for simplicity
};
Enter fullscreen mode Exit fullscreen mode

Quick overview

  • The register() method allows registering an element and applying the appropriate validation rules.
  • The handleSubmit() function will receive the form data if validation is successful.
  • The reset() function will clear all form fields or reset to initial values.
  • In this case, we are using formState to return form errors in an easier way.

Now we have to import Yup into our project and then let's create our schema.

// Hidden for simplicity
import * as yup from "yup";

const schema = yup.object().shape({
  email: yup.string().email().required(),
  password: yup.string().min(8).max(32).required(),
});
Enter fullscreen mode Exit fullscreen mode

Now we have to import @hookform/resolvers so we can use our Yup schema to validate input values. Like this:

import { yupResolver } from "@hookform/resolvers/yup";

// Hidden for simplicity

const App = () => {
  const { register, handleSubmit, formState: { errors }, reset } = useForm({
    resolver: yupResolver(schema),
  });
  return (
    // Hidden for simplicity
};
Enter fullscreen mode Exit fullscreen mode

Now we have to create our function to submit the data (which in this example will be a simple log). Just like we're going to add the reset() method inside our function so that form inputs are cleared as soon as they're submitted.

Lastly let's add the handleSubmit() method to our form. Similar to this:

const App = () => {
  const { register, handleSubmit, formState: { errors }, reset } = useForm({
    resolver: yupResolver(schema),
  });
  const onSubmitHandler = (data) => {
    console.log({ data });
    reset();
  };
  return (
    <form onSubmit={handleSubmit(onSubmitHandler)}>
      // Hidden for simplicity
    </form>
};
Enter fullscreen mode Exit fullscreen mode

The next step is to register our inputs, assigning their names according to the properties of our schema:

const App = () => {
  // Hidden for simplicity
  return (
    <form onSubmit={handleSubmit(onSubmitHandler)}>
      <h2>Lets sign you in.</h2>
      <br />

      <input {...register("email")} placeholder="email" type="email" required />
      <br />

      <input
        {...register("password")}
        placeholder="password"
        type="password"
        required
      />
      <br />

      <button type="submit">Sign in</button>
    </form>
  );
};
Enter fullscreen mode Exit fullscreen mode

Last but not least, let's add the error messages for each of the inputs:

const App = () => {
  // Hidden for simplicity
  return (
    <form onSubmit={handleSubmit(onSubmitHandler)}>
      <h2>Lets sign you in.</h2>
      <br />

      <input {...register("email")} placeholder="email" type="email" required />
      <p>{errors.email?.message}</p>
      <br />

      <input
        {...register("password")}
        placeholder="password"
        type="password"
        required
      />
      <p>{errors.password?.message}</p>
      <br />

      <button type="submit">Sign in</button>
    </form>
  );
};
Enter fullscreen mode Exit fullscreen mode

Now with everything finished, the code should look like this:

import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const schema = yup.object().shape({
  email: yup.string().email().required(),
  password: yup.string().min(8).max(32).required(),
});

const App = () => {
  const { register, handleSubmit, formState: { errors }, reset } = useForm({
    resolver: yupResolver(schema),
  });
  const onSubmitHandler = (data) => {
    console.log({ data });
    reset();
  };
  return (
    <form onSubmit={handleSubmit(onSubmitHandler)}>
      <h2>Lets sign you in.</h2>
      <br />

      <input {...register("email")} placeholder="email" type="email" required />
      <p>{errors.email?.message}</p>
      <br />

      <input
        {...register("password")}
        placeholder="password"
        type="password"
        required
      />
      <p>{errors.password?.message}</p>
      <br />

      <button type="submit">Sign in</button>
    </form>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

In order for you to have an idea of the final result, you should have something similar to what you see in the gif:

result

What about you

What library do you use to validate your forms in React?

Top comments (23)

Collapse
 
ivarskublins profile image
Ivars Kubliņš

Hi! Where did you got that look of form? Some css, which didn't show or it is some inbuilt in hook Forms? How I can use my look then?

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

I used water.css

Collapse
 
roshan_ican profile image
〽️ 𝙍𝙤𝙨𝙝𝙖𝙣

what is that

Collapse
 
canra profile image
Soni Canra Wiguna

it work, thank you so much

Collapse
 
thaoktk profile image
Tran Thu Thao

so usefull thank u very much!!!

Collapse
 
anesunapsta profile image
Anesu Napsta

very usefull, i love yup and this comination with useForms is amazing. Thank you. Do you have another one for Redux/Toolkit

Collapse
 
sorayami profile image
Soraya

Amazing! Thank you for sharing.

Collapse
 
meetmakwana7396 profile image
Meet Makwana

hii, i am using react-hook-form with Typescript

    const schema = yup.object().shape({
        email: yup.string().email().required(),
        password: yup.string().min(8).max(32).required(),
    });

    const { register, handleSubmit, formState } = useForm<IAuthLogin>({
        defaultValues: {
            email: '', // Set initial value for email field
            password: '', // Set initial value for password field
        },
        resolver: yupResolver(schema),
    });
Enter fullscreen mode Exit fullscreen mode

the problem is with typescript it is asking me to add Type for resolver

Image description

Collapse
 
gnganapath profile image
gnganapath

Great explanation. My first search got successfully at dev.to

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thanks for the feedback! I am very happy to hear that the article helped you!

Collapse
 
naskovic profile image
naskovic

Thank you for this tutorial, greate job ;)

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thank you very much for the feedback! 🤗

Collapse
 
fadhilradh profile image
Fadhil Radhian • Edited

Amazing explanation! Thank you so much, you helped me understand this quickly

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thank you very much for the feedback! 💪

Collapse
 
hipstersantos profile image
HipsterSantos

That was really useful , I got it in less than a minute .greate job

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Glad to know and thanks so much for your feedback! 👊

Collapse
 
noor_codes profile image
Noorullah Ahmadzai

Thank You for sharing @franciscomendes10866
I learnt something new today :)

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thanks! I am grateful for your message! ☺️

Collapse
 
moinulmoin profile image
Moinul Moin

any example of using Joi?

Collapse
 
cathat profile image
Nikita E

hi! how check global errors in react-hook form?

Collapse
 
wilmela profile image
Wilmela

Thanks, this was helpful.

Collapse
 
krishnacyber profile image
krishna-Tiwari

and what if we want to show our custom error message can you elaborate clearly for this