How to Perform Form Validation Using Next.js, React Hook Form, and Yup

Build a simple form validation in Next.js using the React Hook Form library and Yup Library.

Picture of Nsikak Imoh, author of Macsika Blog
Abstract background with the text How to Perform Form Validation Using Next.js, React Hook Form, and Yup
Abstract background with the text How to Perform Form Validation Using Next.js, React Hook Form, and Yup

Table of Content

I used React Hook Form for the first time last year and since then, I’ve been in love with it and using it in both React.js and Next.js projects because of the ease of use, flexibility, and lightweight integration.

In this short Next.js code snippet you will learn how to perform form validations in Next.js using the React Hook Form library and Yup.

Although you can use React Hook Form library for validations without the Yup library, this tutorial shows you how to combine the Yup library with React Hook Form library in Next.js.

Read More: What is Next.js On-demand Incremental Static Regeneration and How to Use it?

Example of Form Validation Using Next.js, React Hook Form, and Yup

For this example, we will build a light signup form with common input fields for title, first name, last name, date of birth, email, password, confirm password and accept terms and conditions checkbox.

Here are the criteria we will be validating against in our signup form:

  • All input fields are required, including the checkbox.
  • The date of birth field must be a valid date.
  • The email address field must be in a valid format.
  • The password field must have a min length of 6
  • The confirm password and password fields must match.

We will style it using Bootstrap.

Read More: How to Create a Required Checkbox Using Next.js and React Hook Form

Here is a code example of creating a required checkbox using Next.js and react hook form.

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

export default Home;

function Home() {
    // form validation rules 
    const validationSchema = Yup.object().shape({
        title: Yup.string()
            .required('Title is required'),
        firstName: Yup.string()
            .required('First Name is required'),
        lastName: Yup.string()
            .required('Last name is required'),
        dob: Yup.string()
            .required('Date of Birth is required')
            .matches(/^\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/, 'Date of Birth must be a valid date in the format YYYY-MM-DD'),
        email: Yup.string()
            .required('Email is required')
            .email('Email is invalid'),
        password: Yup.string()
            .min(6, 'Password must be at least 6 characters')
            .required('Password is required'),
        confirmPassword: Yup.string()
            .oneOf([Yup.ref('password'), null], 'Passwords must match')
            .required('Confirm Password is required'),
        acceptTermsandConditions: Yup.bool()
            .oneOf([true], 'You must accept our terms & conditions')
    });
    const formOptions = { resolver: yupResolver(validationSchema) };

    // get functions to build form with useForm() hook
    const { register, handleSubmit, reset, formState } = useForm(formOptions);
    const { errors } = formState;

    function onSubmit(data) {
        // display form data on success
        alert('SUCCESS!! :-)\n\n' + JSON.stringify(data, null, 4));
        return false;
    }

    return (
        <div className="card m-3">
            <h5 className="card-header">Next.js - Form Validation Example</h5>
            <div className="card-body">
                <form onSubmit={handleSubmit(onSubmit)}>
                    <div className="form-row">
                        <div className="form-group col">
                            <label>Title</label>
                            <select name="title" {...register('title')} className={`form-control ${errors.title ? 'is-invalid' : ''}`}>
                                <option value=""></option>
                                <option value="Mr">Mr</option>
                                <option value="Mrs">Mrs</option>
                                <option value="Miss">Miss</option>
                                <option value="Ms">Ms</option>
                            </select>
                            <div className="invalid-feedback">{errors.title?.message}</div>
                        </div>
                        <div className="form-group col-5">
                            <label>First Name</label>
                            <input name="firstName" type="text" {...register('firstName')} className={`form-control ${errors.firstName ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.firstName?.message}</div>
                        </div>
                        <div className="form-group col-5">
                            <label>Last Name</label>
                            <input name="lastName" type="text" {...register('lastName')} className={`form-control ${errors.lastName ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.lastName?.message}</div>
                        </div>
                    </div>
                    <div className="form-row">
                        <div className="form-group col">
                            <label>Date of Birth</label>
                            <input name="dob" type="date" {...register('dob')} className={`form-control ${errors.dob ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.dob?.message}</div>
                        </div>
                        <div className="form-group col">
                            <label>Email</label>
                            <input name="email" type="text" {...register('email')} className={`form-control ${errors.email ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.email?.message}</div>
                        </div>
                    </div>
                    <div className="form-row">
                        <div className="form-group col">
                            <label>Password</label>
                            <input name="password" type="password" {...register('password')} className={`form-control ${errors.password ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.password?.message}</div>
                        </div>
                        <div className="form-group col">
                            <label>Confirm Password</label>
                            <input name="confirmPassword" type="password" {...register('confirmPassword')} className={`form-control ${errors.confirmPassword ? 'is-invalid' : ''}`} />
                            <div className="invalid-feedback">{errors.confirmPassword?.message}</div>
                        </div>
                    </div>
                    <div className="form-group form-check">
                        <input name="acceptTermsandConditions" type="checkbox" {...register('acceptTermsandConditions')} id="acceptTermsandConditions" className={`form-check-input ${errors.acceptTermsandConditions ? 'is-invalid' : ''}`} />
                        <label htmlFor="acceptTermsandConditions" className="form-check-label">Accept Terms & Conditions</label>
                        <div className="invalid-feedback">{errors.acceptTermsandConditions?.message}</div>
                    </div>
                    <div className="form-group">
                        <button type="submit" className="btn btn-primary mr-1">Register</button>
                        <button type="button" onClick={() => reset()} className="btn btn-secondary">Reset</button>
                    </div>
                </form>
            </div>
        </div>
    );
}
Highlighted code sample.

Explanation of Code Example

We built a Next.js Home Component and import the needed functions in React Hook Form and Yup validation library.

We defined the validation rules of the form using the Yup schema validation library.

We then sent the output to the React Hook Form useForm() function using the formOptions property in Yup.

The checkbox is set to required with the validation rule from using Yup as Yup.bool().oneOf([true], 'You must accept terms & conditions.').

The useForm() hook function from React Hook form returns an object with methods for working with a form such as registering form inputs, handling form submission, resetting the form, accessing form state, displaying errors, and more.

We call onSubmit() method from React Hook form when the form passes all validations and gets submitted.

This point is where you send an update or post data to the API endpoint that does something with the form data.

In this example, when the form successfully passes all validations and gets submitted, we simply display the form data in a JavaScript alert.

The returned JSX template contains the form with all the input fields and validation messages.

The form fields are registered with the React Hook Form by calling the register function with the field name from each input element (e.g. {...register('title')}).

Read More: How to Resolve the Module not found: Can’t resolve ‘fs’ error in Next.js and WebPack

Wrap Off

In this short tutorial, we looked at how to build a simple form validation in Next.js using the React Hook Form library and Yup Library.

Our example is a signup form that requires all input fields to be provided including the checkbox, the date of birth must be a valid date, the email address field must be in a valid format, the password field must have a minimum length of six, and the confirm password and password fields must be the same.

Validations were done using the Yup library.

If you learned in this tutorial, please consider sharing and subscribing to our newsletter.

Connect with me.

Need an engineer on your team to grease an idea, build a great product, grow a business or just sip tea and share a laugh?