DEV Community

Cover image for How to Validate Forms with React Hook Form in React Apps
David Asaolu
David Asaolu

Posted on • Originally published at beginnerfriendly.hashnode.dev

How to Validate Forms with React Hook Form in React Apps

Validating inputs from forms is very important to keep a clean and organized backend service. If you have to write a program that validates and handles form input based on different cases, this can be a difficult task. But with React Hook Form, we worry less about how to handle errors from web forms.

React Hook Form is a library that enables us to accept only valid data from the user. With React Hook Form, we can create performant React forms, which validate form inputs and make sure they are in the exact format required by the server.

In this tutorial, I will guide you through the process of validating data from your React forms using React Hook Form.

Setup a React project

  • Open your terminal and run the command below to create a React app project
npx create-react-app reacthookform
Enter fullscreen mode Exit fullscreen mode
  • Install React Hook Form. After installing React Hook Form, skip to the next section if you're not using Tailwind CSS.
npm install react-hook-form
Enter fullscreen mode Exit fullscreen mode
  • Optional: Install Tailwind CSS by running the command below. Tailwind CSS is utility-first CSS framework for building mordern user interfaces.
  npm install -D tailwindcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode
  • Generate tailwind.config.js and postcss.config.js configuration files by running:
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode
  • Open tailwind.config.js and copy the code below:
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};
Enter fullscreen mode Exit fullscreen mode
  • In the ./src/index.css file, add Tailwind directive to your CSS:
@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

React Hook Form Validation

I will explain this concept by creating a user registration form that accepts different information from the user, such as first name, last name, age, gender, email address, and password.

A popular way to handle these inputs in React is to keep all the data in a state, but React Hook Form provides a more efficient way of handling the form data.

Let's examine the code below:

import { useForm } from 'react-hook-form';

export default function Home() {
  const { register, handleSubmit } = useForm();

  const submitForm = (data) => {
    console.log(data);
  };

  return (
    <div>
      <main className="flex items-center justify-center py-8 min-h-screen">
        <form
          onSubmit={handleSubmit(submitForm)}
          className="flex flex-col w-[500px] gap-4"
        >
          <label htmlFor="firstName">First Name</label>
          <input
            type="text"
            className="border-2 py-2 px-4"
            {...register('firstName')}
          />

          <label htmlFor="lastName">Last Name</label>
          <input
            type="text"
            className="border-2 py-2 px-4"
            {...register('lastName')}
          />
          <label htmlFor="age">Age</label>
          <input
            type="number"
            className="border-2 py-2 px-4"
            {...register('age')}
          />

          <select {...register('gender')} className="border-2 py-2 px-4">
            <option value="female">Female</option>
            <option value="male">Male</option>
            <option value="others">Others</option>
          </select>

          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            className="border-2 py-2 px-4"
            {...register('email')}
          />

          <label htmlFor="password">Password</label>
          <input
            type="password"
            className="border-2 py-2 px-4"
            {...register('password')}
          />

          <button
            className="py-2 px-4 border bg-slate-300 hover:bg-slate-500 hover:text-slate-50"
            type="submit"
          >
            Submit
          </button>
        </form>
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The code snippet above introduces a hook called useForm, which contains the functions register and handleSubmit.

  • useForm() is a custom hook in React Form Hook used for managing forms with ease. You can find some optional arguments here
  • register("variable_name") is a function that accepts the name of the input field as an argument. This argument represents the property name of the input field.
  • handleSubmit() is function that wraps the submit function. It handles validation of the data provided by the user before sending it to the server.

How then can we validate the user input?

The register() function is used to validate form inputs. It accepts two arguments - the property name of the input field and the validation rules. A validation rule is an object containing the set of rules to be met by each input field, as well as the error messages to display when the rules are not met.

Let's take a look at an example
I will be using the user registration form we created earlier to explain this concept.

import { useForm } from 'react-hook-form';

export default function Home() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const submitForm = (data) => {
    console.log(data);
  };

  return (
    <div>
      <main className="flex items-center justify-center py-8 min-h-screen">
        <form
          onSubmit={handleSubmit(submitForm)}
          className="flex flex-col w-[500px] gap-4"
        >
          <label htmlFor="firstName">First Name</label>
          <input
            type="text"
            className="border-2 py-2 px-4"
            {...register('firstName', {
              required: 'Please enter your first name',
            })}
          />
          {/* --- displays error message for first name */}
          {errors?.firstName && (
            <p className="text-red-500">{errors.firstName.message}</p>
          )}

          <label htmlFor="lastName">Last Name</label>
          <input
            type="text"
            className="border-2 py-2 px-4"
            {...register('lastName', {
              required: 'Please enter your last name',
            })}
          />
          {/* --- displays error message for last name */}
          {errors?.lastName && (
            <p className="text-red-500">{errors.lastName.message}</p>
          )}

          <label htmlFor="age">Age</label>
          <input
            type="number"
            className="border-2 py-2 px-4"
            {...register('age', {
              required: 'Please enter your age',
              valueAsNumber: true,
              min: {
                value: 16,
                message: 'You must be greater than 15',
              },
            })}
          />
          {/* --- displays error message for age */}
          {errors?.age && <p className="text-red-500">{errors.age.message}</p>}

          <select
            {...register('gender', { required: 'Please provide your gender' })}
            className="border-2 py-2 px-4"
          >
            <option value="female">Female</option>
            <option value="male">Male</option>
            <option value="others">Others</option>
          </select>
          {/* --- displays error message for gender */}
          {errors?.gender && (
            <p className="text-red-500">{errors.gender.message}</p>
          )}

          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            className="border-2 py-2 px-4"
            {...register('email', { required: 'Please enter a valid enail' })}
          />
          {/* ---displays error message for email */}
          {errors?.email && (
            <p className="text-red-500">{errors.email.message}</p>
          )}

          <label htmlFor="password">Password</label>
          <input
            type="password"
            className="border-2 py-2 px-4"
            {...register('password', {
              required: 'Please enter your password',
              minLength: {
                value: 8,
                message: 'Your password must contain at least 8 characters',
              },
            })}
          />
          {/* ---displays error message for password */}
          {errors?.password && (
            <p className="text-red-500">{errors.password.message}</p>
          )}

          <button
            className="py-2 px-4 border bg-slate-300 hover:bg-slate-500 hover:text-slate-50"
            type="submit"
          >
            Submit
          </button>
        </form>
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

From the code snippet above,

  • I imported formState: { errors } - an object containing the validation rules and error messages for each of the registered form input from useForm().
  • The validation rule in the register() function has the property of required- meaning the form fields are important, and if they are left empty, it displays the error message - which is the value of the required property.
  • In age, the register() function has the required property - valueAsNumber and min. valueAsNumber converts the user's input to a data type of Number. min is an object containing two keys - value and message. value contains the minimum value the form accepts and message is a custom error message you will like to show the user.
  • For the password, the register() function has the key - minLength which is an object with two keys, value and message. value refers to the number of characters and message is the error message to displayed if the number of characters is not upto the required value.

Conclusion

According to https://react-hook-form.com, React Hook Form reduces the amount of code you need to write while removing unnecessary re-renders, so you don't have to worry about performance issues. React Hook Form optimizes the performance of your React forms. With lesser code, you can build faster and more optimized web forms.

Thank you for reading!

arshadayvid image

Writer's Corner

Hi, I am open to freelance technical writing gigs and remote opportunities. Let's work together. 📧: asaoludavid234@gmail.com

Feel free to connect with me on Twitter and LinkedIn

Discussion (0)