Published: 1 June 2023
Introduction
When it comes to building forms in React, React Hook Form has quickly become one of the most popular choices due to its simplicity and performance. But when combined with Zod for validation, it unlocks a new level of type-safety, ensuring that your form validation is both reliable and tightly integrated with TypeScript.
In this post, we’ll explore why React Hook Form + Zod is the best validation combo for building type-safe forms in React, particularly when working with Next.js. We’ll guide you through setting it up, handling form validation, and ensuring that everything is type-safe for a seamless developer experience.
Why React Hook Form + Zod is the Best Validation Combo
1. Simplicity and Performance
React Hook Form (RHF) is widely praised for its minimal re-renders and lightweight API. It significantly improves form performance by only re-rendering the individual fields that are changed, rather than the entire form. This makes it a great fit for large and complex forms. By integrating it with Zod, you get a concise and efficient validation mechanism that works seamlessly with TypeScript.
2. Type-Safety with Zod
Zod is a TypeScript-first schema validation library that provides strict type inference and allows for defining schemas with validation logic directly in TypeScript. When you use Zod with React Hook Form, the form fields’ types are automatically inferred, reducing manual type definitions and ensuring that your forms are type-safe from the start.
This combination brings major benefits:
- Automatic Type Inference: Zod validates your inputs and automatically updates types.
- Centralized Validation Logic: With Zod schemas, you can manage all form validation in one place.
- Error Handling: Zod offers a built-in mechanism for handling errors and showing messages based on the validation rules.
3. Improved Developer Experience
The integration of React Hook Form with Zod is a huge win for developers, especially when using TypeScript. You don’t have to define types separately for form inputs, validation, and state, reducing redundancy. The schema validation is concise, and you can easily handle complex validation logic directly inside Zod schemas.
Setting Up React Hook Form with Zod
Let’s walk through the process of integrating React Hook Form and Zod in a Next.js app.
Step 1: Install the Necessary Packages
To get started, you need to install both React Hook Form and Zod:
npm install react-hook-form zod @hookform/resolvers
We’re also installing @hookform/resolvers
to connect Zod with React Hook Form.
Step 2: Define a Zod Schema for Validation
Now, let’s define a Zod schema to validate our form. Zod provides a powerful, declarative way to define your validation rules.
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2, "Name is required and must be at least 2 characters."),
email: z.string().email("Please enter a valid email address."),
age: z.number().min(18, "You must be at least 18 years old."),
});
export default schema;
Here we have defined three fields: name
, email
, and age
. Each field has its own validation logic. Zod will automatically check whether these rules are followed and return the corresponding error messages.
Step 3: Create the Form Component
Now, let’s set up the form component with React Hook Form and Zod. We will use the useForm
hook from React Hook Form, and pass in the Zod schema via @hookform/resolvers/zod
.
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import schema from './validationSchema';
const Form = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema), // Hooking up Zod schema with React Hook Form
});
const onSubmit = (data: any) => {
console.log('Form Data:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Name</label>
<input {...register('name')} />
{errors.name && <span>{errors.name.message}</span>}
</div>
<div>
<label>Email</label>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
</div>
<div>
<label>Age</label>
<input type="number" {...register('age')} />
{errors.age && <span>{errors.age.message}</span>}
</div>
<button type="submit">Submit</button>
</form>
);
};
export default Form;
Explanation:
- useForm: The
useForm
hook initializes the form. Theresolver
prop is used to connect React Hook Form with Zod through thezodResolver
function. - register: This is used to register form fields with React Hook Form.
- formState.errors: This object contains validation error messages that are displayed when the input does not pass the Zod validation schema.
- handleSubmit: This function is used to trigger form submission. If validation fails, the errors will be shown; otherwise, the form data will be logged to the console.
Integrating with Next.js
1. Setup in a Next.js Page
To integrate this form into a Next.js app, you can create a new page or add it to an existing one. Here’s how you could integrate the form into a Next.js page:
import Form from '../components/Form';
const ContactPage = () => {
return (
<div>
<h1>Contact Us</h1>
<Form />
</div>
);
};
export default ContactPage;
2. Handling Server-Side Form Submission
For server-side form submission in Next.js, you could use API routes. Here’s how you might handle form submission on the server:
Create an API route inside the pages/api
folder, such as pages/api/contact.ts
.
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { name, email, age } = req.body;
// Handle form submission logic (e.g., send email, save to database)
res.status(200).json({ message: 'Form submitted successfully!' });
} else {
res.status(405).json({ message: 'Method Not Allowed' });
}
}
Make sure to update your form’s onSubmit
function to send data to this API route.
Conclusion
Integrating React Hook Form with Zod provides a powerful solution for building type-safe, performant forms in React, especially when working with Next.js. By combining React Hook Form’s minimal re-rendering with Zod’s type-safe schema validation, you can improve both the developer experience and the reliability of your forms.
With this setup, you get all the benefits of automatic type inference, centralized validation logic, and a clean API for managing forms. Whether you’re building simple forms or more complex ones with async validation, this combo is the way forward for modern React apps.