Zod with React Hooks

abdul ahad
4 min read5 days ago

--

This setup allows you to validate your form inputs using Zod’s schema validation while leveraging RHF’s form management.

Photo by Berkay Gumustekin on Unsplash

Step-by-Step Guide to Zod and React Hook Form Integration

1. Install Necessary Dependencies

You need to install React Hook Form, Zod, and a resolver that connects the two.

npm install react-hook-form zod @hookform/resolvers
  • react-hook-form handles form state and submission.
  • zod is used for schema validation.
  • @hookform/resolvers provides a bridge between Zod and React Hook Form.

2. Define the Zod Schema

Create a Zod schema that defines the structure and validation rules for your form data.

import { z } from 'zod';

const formSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters long"),
email: z.string().email("Invalid email address"),
age: z.number().min(18, "You must be at least 18 years old"),
});

In this schema:

  • name is a string with a minimum length of 2 characters.
  • email must be a valid email address.
  • age is a number with a minimum value of 18.

3. Set Up React Hook Form with Zod Resolver

Now, create the form using React Hook Form. The zodResolver from @hookform/resolvers/zod will connect the Zod schema to RHF, so validation is handled by Zod.

import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";

// Define the Zod schema
const formSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters long"),
email: z.string().email("Invalid email address"),
age: z.number().min(18, "You must be at least 18 years old"),
});
type FormData = z.infer<typeof formSchema>;

export default function MyForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(formSchema), // Use Zod resolver
});

const onSubmit = (data: FormData) => {
console.log("Form data:", data); // Handle form submission
};

return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
{/* Name field */}
<div>
<label
htmlFor="name"
className="block text-sm font-medium text-gray-700"
>
Name:
</label>
<input
{...register("name")}
id="name"
className="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
/>
{errors.name && (
<p className="mt-1 text-sm text-red-600">{errors.name.message}</p>
)}
</div>

{/* Email field */}
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-gray-700"
>
Email:
</label>
<input
{...register("email")}
id="email"
className="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
/>
{errors.email && (
<p className="mt-1 text-sm text-red-600">{errors.email.message}</p>
)}
</div>

{/* Age field */}
<div>
<label
htmlFor="age"
className="block text-sm font-medium text-gray-700"
>
Age:
</label>
<input
type="number"
{...register("age", { valueAsNumber: true })}
id="age"
className="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
/>
{errors.age && (
<p className="mt-1 text-sm text-red-600">{errors.age.message}</p>
)}
</div>

<button
type="submit"
className="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Submit
</button>
</form>
);
}

Explanation of Key Components:

  1. useForm Hook with Zod Resolver:
  • useForm is used to initialize the form with the zodResolver, which automatically applies the Zod schema for validation.
  • register is used to bind the form fields to React Hook Form's internal state management.
  • handleSubmit is used to trigger validation and form submission.
  • errors is populated if there are any validation issues (directly from Zod).
  1. Form Inputs: Each input field is registered using register("fieldName"), which tracks the input state and links it to the form's state in React Hook Form. For example:
  • register("name") links the name input to the form state.
  • If a validation error occurs, the errors object will contain the error message generated by Zod.
  1. Error Handling: If Zod’s validation fails for any field, an error message is stored in errors[fieldName].message. This message is rendered below each form field when there's a validation error.

Example Breakdown:

  • If the user enters fewer than 2 characters for name, the Zod schema will trigger an error, and "Name must be at least 2 characters long" will appear under the input field.
  • If the email is not a valid format (e.g., missing @), Zod will generate the error "Invalid email address", and this will be displayed.
  • If the user enters an age below 18, Zod will trigger the error "You must be at least 18 years old".

4. Final Form Functionality

  • When the form is submitted, the onSubmit function is triggered if all fields pass validation.
  • The form’s data is printed to the console, or you can further process the data as needed.

Key Points:

  • Schema-Driven Validation: Zod handles all validation based on the schema you define.
  • Integration: RHF manages form state and submissions, while Zod checks the form data against the schema.
  • Errors: Validation errors from Zod are displayed in the form using React Hook Form’s errors object.

This combination provides a powerful way to manage forms with clear, schema-driven validation rules while maintaining a clean and efficient React form structure.

github reference: https://github.com/abdahad1996/ReactLearning

--

--

abdul ahad

A software developer dreaming to reach the top and also passionate about sports and language learning