From Zero to Hero: Build React Forms with Validation Using React Hook Form and Yup

chintanonweb - Oct 17 - - Dev Community

How to Build a React Form Using React Hook Form and Yup Validation: A Step-by-Step Guide

Introduction

React Hook Form is a powerful tool that simplifies form handling in React. In combination with Yup, a validation library, you can create robust, validated forms easily. Whether you're a beginner or just need a refresher, this guide will walk you through the process step-by-step, providing all the examples and explanations you need to build a working sign-in form with validation.

Why Use React Hook Form?

React Hook Form focuses on providing the best performance and reducing unnecessary re-renders, making it a lightweight alternative to other form libraries. When you add Yup for schema validation, it becomes a strong tool to handle complex validations in a clean and scalable way.

Key Features:

  • Simple form handling with minimal code.
  • Built-in support for validation.
  • Reduced re-renders to enhance performance.
  • Easy integration with Yup for schema-based validation.

Let’s start building the form!


Step 1: Install Necessary Packages

Before you start coding, you need to install the required libraries: react-hook-form, @hookform/resolvers, and Yup.

Run the following command in your project:

npm install react-hook-form @hookform/resolvers yup
Enter fullscreen mode Exit fullscreen mode
  • react-hook-form: Provides hooks for handling forms in React.
  • @hookform/resolvers: Connects Yup with react-hook-form.
  • Yup: A JavaScript schema builder for value parsing and validation.

Step 2: Define the Form Inputs

Create the input fields that will be part of the form. For a basic sign-in form, we'll have two fields: email and password.

Example of the Input Interface:

// Define the structure of form inputs
interface IFormInput {
  email?: string;
  password?: string;
}
Enter fullscreen mode Exit fullscreen mode

Here, we define an interface IFormInput that includes optional properties for email and password. This interface ensures type safety when handling form data.


Step 3: Create a Dynamic Validation Schema with Yup

For validation, we'll use Yup to define rules for each input. You can customize this schema as needed. Here’s how to dynamically generate it based on field configurations.

Sign-In Field Configurations:

// Configurations for each field's validation
export const signInfieldConfigs = {
  email: {
    type: "string",
    required: "Email is required",
    matches: {
      regex: /^[\w.-]+@[\w-]+\.[\w-]{2,4}$/,
      message: "Please enter a valid email address",
    },
  },
  password: {
    type: "string",
    required: "Password is required",
    matches: {
      regex:
        /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,20}$/,
      message: "Password must contain at least one uppercase, one lowercase, one number, and one special character",
    },
    min: {
      value: 6,
      message: "Password must be at least 6 characters",
    },
    max: {
      value: 20,
      message: "Password must not exceed 20 characters",
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

These configurations define the validation rules for email and password fields, such as regex patterns, required fields, and length restrictions.

Generate Validation Schema:

import * as Yup from "yup";

export const generateValidationSchema = (fieldConfigs: any) => {
  const shape: any = {};

  Object.keys(fieldConfigs).forEach((key) => {
    const config = fieldConfigs[key];
    let fieldSchema = Yup.string(); // Default to string type

    if (config.required) {
      fieldSchema = fieldSchema.required(config.required);
    }

    if (config.matches && config.matches.regex) {
      fieldSchema = fieldSchema.matches(config.matches.regex, config.matches.message);
    }

    if (config.min) {
      fieldSchema = fieldSchema.min(config.min.value, config.min.message);
    }

    if (config.max) {
      fieldSchema = fieldSchema.max(config.max.value, config.max.message);
    }

    shape[key] = fieldSchema;
  });

  return Yup.object().shape(shape);
};
Enter fullscreen mode Exit fullscreen mode

Here, the generateValidationSchema function dynamically creates a Yup schema based on the configurations provided for each field.


Step 4: Set Up React Hook Form

Now, integrate react-hook-form with the validation schema.

import { SubmitHandler, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

// Create the form component
const SignIn = () => {
  const validationSchema = generateValidationSchema(signInfieldConfigs);

  // Initialize the form with useForm hook
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<IFormInput>({
    resolver: yupResolver(validationSchema),
  });

  // Handle form submission
  const onSubmit: SubmitHandler<IFormInput> = (data) => {
    console.log(data);
  };

  return (
    <div className="form-container">
      <form onSubmit={handleSubmit(onSubmit)}>
        {/* Email Field */}
        <input
          {...register("email")}
          placeholder="Email Address"
        />
        {errors.email && <p>{errors.email.message}</p>}

        {/* Password Field */}
        <input
          {...register("password")}
          type="password"
          placeholder="Password"
        />
        {errors.password && <p>{errors.password.message}</p>}

        {/* Submit Button */}
        <button type="submit">Sign In</button>
      </form>
    </div>
  );
};

export default SignIn;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • The useForm hook initializes form management with a resolver for validation.
  • register is used to register form inputs with React Hook Form.
  • handleSubmit handles form submission, calling the onSubmit function when the form is valid.
  • Validation errors are accessible through formState.errors, which is automatically populated if validation fails.

Step 5: Display Validation Errors

In this step, ensure that any validation errors are displayed to the user in an understandable way. Here, we use a custom component InputError to show the errors.

const InputError = ({ error }: { error?: string }) => {
  return error ? <p className="error-text">{error}</p> : null;
};
Enter fullscreen mode Exit fullscreen mode

The InputError component simply takes the error message and displays it when it exists.


Step 6: Add CSS for Better UI

Make sure to add some styles to improve the user experience:

.form-container {
  max-width: 500px;
  margin: auto;
  padding: 2rem;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

input {
  width: 100%;
  padding: 0.8rem;
  margin-bottom: 1rem;
  border-radius: 4px;
  border: 1px solid #ccc;
}

button {
  width: 100%;
  padding: 0.8rem;
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.error-text {
  color: red;
  font-size: 0.9rem;
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Test the Form

Test your form by entering invalid and valid data to ensure that the validation messages are shown correctly. For example:

  • If you enter an invalid email, the message "Please enter a valid email address" should appear.
  • If you enter a password that doesn't meet the criteria, you'll see "Password must contain at least one uppercase, one lowercase, one number, and one special character."

FAQs

What Happens if Validation Fails?

If validation fails, the errors object inside formState is populated with the corresponding error messages for each field. These errors can be displayed to the user.

Can I Add More Fields?

Yes, you can add more fields to the form and update the validation schema accordingly. For example, you could add a username field with its own validation rules.


Conclusion

You’ve now successfully created a sign-in form in React using react-hook-form and Yup for validation. This form handles validation dynamically and can be easily extended to include more fields. By following the steps above, even beginners can create complex forms with minimal effort and ensure a smooth user experience.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .