How to Handle Forms and Validation in React with React Hook Form and Zod
Forms are essential to most web applications, whether you're collecting user information, managing logins, or processing payments. However, managing forms efficiently in React can be challenging, especially regarding validation. React Hook Form is a powerful library that simplifies form handling. Combined with Zod, a schema validation library, it makes building and validating forms easy and reliable.
This step-by-step tutorial will show you how to handle forms and validation in React using React Hook Form and Zod.
Step 1: Setting Up React Hook Form
Before we begin, make sure you have a React project ready. If you don't, you can create one using:
npx create-react-app form-validation-tutorial
cd form-validation-tutorial
Next, install React Hook Form and Zod by running the following command:
npm install react-hook-form zod @hookform/resolvers
Step 2: Creating a Simple Form
Let’s start by creating a simple form with fields like email and password. In your App.js
(or App.tsx
for TypeScript) file, add the following:
import React from "react";
import { useForm } from "react-hook-form";
const App = () => {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
console.log("Form Data:", data);
};
return (
<div>
<h1>Simple Form</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Email:</label>
<input {...register("email")} type="email" />
</div>
<div>
<label>Password:</label>
<input {...register("password")} type="password" />
</div>
<button type="submit">Submit</button>
</form>
</div>
);
};
export default App;
How it works:
useForm()
provides methods likeregister
andhandleSubmit
.register
connects form inputs to React Hook Form's internal state.handleSubmit
handles the form submission process.
Step 3: Adding Validation with Zod
Zod helps us define a schema for form validation. To integrate it with React Hook Form, follow these steps:
Import
zod
and thezodResolver
from@hookform/resolvers
.Define a schema using Zod.
Pass the schema to the
useForm
hook.
Here’s the updated code:
import React from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
const schema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(6, "Password must be at least 6 characters"),
});
const App = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
const onSubmit = (data) => {
console.log("Form Data:", data);
};
return (
<div>
<h1>Form with Validation</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Email:</label>
<input {...register("email")} type="email" />
{errors.email && <p>{errors.email.message}</p>}
</div>
<div>
<label>Password:</label>
<input {...register("password")} type="password" />
{errors.password && <p>{errors.password.message}</p>}
</div>
<button type="submit">Submit</button>
</form>
</div>
);
};
export default App;
How it works:
The
schema
defines validation rules for each field.zodResolver
connects Zod to React Hook Form.formState.errors
contains validation errors for each field.
Step 4: Handling Errors
We’ve already added error messages in the form, but let’s explain it in detail:
Use
errors.email
orerrors.password
to check if there’s an error in the respective field.Use
{errors.fieldName.message}
to display the error message defined in the Zod schema.
For example:
{errors.email && <p>{errors.email.message}</p>}
Step 5: Submitting the Form
When the form is valid, the onSubmit
function is called. You can process the form data here by sending it to an API or saving it locally.
Here’s how you can simulate submitting data to an API:
const onSubmit = async (data) => {
try {
const response = await fetch("https://api.example.com/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
console.log("API Response:", await response.json());
} catch (error) {
console.error("Error submitting form:", error);
}
};
Step 6: Best Practices
- Use Default Values: Initialize your form fields with default values.
const { register, handleSubmit } = useForm({
defaultValues: { email: "", password: "" },
});
Keep Forms Simple: Avoid adding too many fields in one form. Split long forms into steps.
Error Feedback: Display clear and specific error messages for a better user experience.
Accessibility: Add appropriate
aria
attributes to inputs for better accessibility.
Using React Hook Form with Zod makes handling forms in React easy. React Hook Form efficiently manages form state, while Zod simplifies validation with its powerful schema definition. Together, they allow developers to build robust and user-friendly forms with minimal effort.
Now that you know how to handle forms and validation, you can further explore features like multi-step forms, file uploads, or integrating authentication systems.
Happy coding! 🎉