Zod validation with React Hook Form

Published on January 30, 2025

Zod validation with React Hook Form

Form validation is an integral part of applications that collect data from users.

Forms that authenticate users, collect addresses for shipping, allow users to select booking dates, and anything else you can think of, should all verify that the data they collect is complete, accurate, and in the correct format. Form validation helps to maintain security, keeps data consistent, and provides feedback to users so they can correct information before submitting it, improving the user experience.

This post demonstrates form validation in React using Zod validation with React Hook Form, and provides full code examples demonstrating how you can use Zod validation in your own projects.

What is Zod validation?

Zod is a schema validation library that has a TypeScript-first approach, offering developers an elegant way to define and enforce data structures. Zod stands out by providing a way to generate TypeScript types directly from its schemas, so that you don't need to write identical but redundant type definitions for different purposes. Zod also provides runtime type safety in JavaScript projects without the need for TypeScript, making it useful for a wide range of projects.

What sets Zod apart from other libraries is its extensive API, which mirrors TypeScript's capabilities for type inference and manipulation, making it great for larger, more complex applications. In React, Zod schemas can be used to validate form data and provide error handling, improving user experience.

How to use Zod for form validation in React

When building forms for websites and apps, it's best practice to guarantee type safety and the correct format for collected data to stop users from submitting incorrect or incomplete data. This prevents errors both at runtime and further down the track when you attempt to process or analyze the submitted data. You can achieve this by combining Zod's schema validation with React Hook Form.

React Hook Form is a lightweight React form library that simplifies form building and validation in React. It uses React hooks for form state management, minimizing re-renders, and improving performance. When paired with React Hook Form, Zod streamlines implementing form validation by integrating validation logic and type safety. Combined with the efficient form handling of React Hook Form, this reduces the risk of inconsistencies in validation rules.

While it is absolutely vital that your back ends validate all data (it's worth noting here that Zod can also be used in server environments, further allowing you to re-use the same schema code) to minimize any security vulnerabilities such as SQL injection, your front ends should also validate data. 

Validation on the front end should never be relied on for backend and database security, as the client-side validation is trivial to bypass (as the user has control of the web browser they're using). However, implementing frontend validation prevents users getting frustrated and wasting server resources with repeated form submissions that contain invalid data that cannot be used. For example, if a user mistakenly enters an email of userexample.com instead of user@example.com into a registration form, it would be better to catch that on the client than to send it to the server, wasting resources to generate an error, and then finally tell the user.

Flow diagram showing Zod validation in a React application, with frontend integration using react-hook-form, Zod schemas for validation, and backend validation for final data checks.

What can Zod form validation with React Hook Form check for?

Zod provides the following schema validations out of the box. These can then be used with React Hook Form to notify the user if they have made a mistake when inputting data:

  • Required fields: Ensure that all mandatory inputs are filled.

  • Data types: Confirm that values match the expected types (numbers, strings).

  • Value ranges: Validate that numbers and dates fall within a specified limit.

  • Data validity: Check that URLs, emails, or phone numbers adhere to the correct format.

  • Length constraints: Enforce minimum and maximum character limits for text fields.

  • Cross-field validation: Validate relationships between fields, such as ensuring "Confirm password" matches the original password.

Code examples: Basic Zod validation syntax

Zod provides developer-friendly schema validation syntax that combines simplicity with practicality, as demonstrated in the Zod schema code examples below.

Common validation syntax: The Zod API lets you validate data structures like strings, numbers, and booleans.

Zod schemas: Schemas define the expected shape and constraints of data objects. Schemas form the foundation for all Zod validations — for example, the userSchema below defines a valid user data type, including its properties.

Error message customization: You can provide custom error messages for when what the user enters doesn't match your schema requirements, and these can then be obtained and displayed with React Hook Form.

Validating objects with Zod schemas: Once you have defined a schema you can parse your data through it to make sure it meets the requirements.

Validating nested objects and arrays: Zod validation supports data structures like objects and arrays, allowing you to validate multiple nested objects.

In the above example, userSchema defines a validation for a nested user object, and highScoresSchema defines an array where each element has a user field validated with the userSchema and a score field which must be a positive number. The example data is defined and then validated using the highScoresSchema.

Custom validation: Zod allows you to define custom validation logic with the .refine function for use cases that aren't met with its included functionality. The below example validates that a VAT (sales tax) number conforms to a given specification.

Zod schema derivation: You can extend schemas from your existing ones to promote code reusability.

The extendedVatNumberSchema now contains the additional refinement to ensure only digits follow “VAT” so using this schema ensures the string starts with “VAT” and is followed by digits.

Zod field value transformations: You can transform data as part of the validation process.

const trimmedString = z.string().transform((val) => val.trim());

When validating this string the trim() function removes any whitespace characters from the beginning and end of the string.

Data fetching and parsing in Zod validation: Zod can validate data retrieved from an external source using schema.parse. This function validates the data against the defined schema but also throws an error if the data doesn’t conform to the defined structure.

In the above example, the schema ensures that apiResponse contains an object with a key called data, which must be an array of strings.

TypeScript type inference: Zod can create TypeScript types by inferring them from its own schemas:

In the above example, userSchema is a Zod schema that defines the shape of a user object, and the z.infer utility extracts the TypeScript type from the schema definition (essentially translating the schema into a corresponding TypeScript type). The z.infer line is equivalent to:

Zod validation tutorial: React Hook Form + Zod

This tutorial will guide you through creating an invoice generator in React using Zod validation and React Hook Form for the form handling.

This Zod validation tutorial covers:

  • Setting up Zod and React Hook Form in your React project.

  • Defining schemas and integrating them with Zod and TypeScript.

  • Implementing complex validations, including cross-field and dynamic field validations.

  • Building a fully functional invoice generator that validates form data.

You can see the full working example code for this tutorial here.

Step 1: Initialize Zod, React Hook Form and TypeScript

You can initialize a new React TypeScript project with Vite and then install the necessary react-hook-form and zod libraries, as well as the React Hook Form resolvers that integrate external validation libraries like Zod with React Hook Form:

npm install react-hook-form zod @hookform/resolvers

Step 2: Define the Zod schema

Create a file named schema.ts in the src directory of your project and add the following code to define the schema for the invoice form:

The above example defines a Zod schema (invoiceSchema) for validating the invoice form, which specifies requirements and error messages for the fields of the form:

  • Customer and Address fields: Must not be empty.

  • Dates: Must have a valid date format.

  • Line items: Must include at least one item with a description, a quantity of at least 1, and a price greater than 0.01.

It then uses type inference to export the schema as a reusable InvoiceFormValues type.

Step 3: Integrate the Zod schema with React Hook Form

Next, build the form using React Hook Form and integrate the Zod schema by updating your src/App.tsx file (if you created your project using Vite) to contain the following:

The TypeScript types and Zod validation for the form are defined in the useForm function along with the default values. The useFieldArray hook is then used to get the fields, and the append and remove functions so the user can append new lines and remove them for the invoice. Then the field is built by mapping out the field values from React Hook Form.

Step 4: Add error messages with React Hook Form

Notice that if you haven't filled out all values, the form won't submit but instead fails silently. That's because you need to add the error messages that were defined in the schema. To do this, update your src/App.tsx file to contain the following:

The above code updates App.tsx to include errors by destructuring the error object from the formState and then checking each line if the error is present; if it is, it displays the error message text which was defined in the schema.

For example, the following validation code is added for the customerName field:

If the errors object has a customerName property, the error will be displayed.

Step 5: Add cross-field Zod validation

With cross-field validation, Zod can check that the due date is on or after the invoice date and display a message to the user if it’s not. To do this, replace the code in the schema.ts file with the following:

The above code chains the refine function on to the end of the object validation definition and makes a custom check to make sure the invoice date is not before the current date and that the due date is not before the invoice date; these errors will now be displayed to the user.

Step 6: Validate unique descriptions for line items

You can validate that each description for the line item in the invoice is unique using superRefine. To do this, update the schema.ts file, adding the superRefine function in the below snippet to the lineItems schema.

The above code checks each description from the line items array and makes sure there are no duplicates. If validation fails, an error message is added with ctx.addIssue.

Server-side validation for React apps with Zod

Seeing as the front end can be completely bypassed (through malicious tampering), you need to add input validation to your back end to avoid security vulnerabilities such as SQL injection. You can use Zod validation to check inputs on the server after submission.

Here's a basic example of server-side validation using Zod:

The code example above defines a schema with Zod, then defines a function to which you can pass the incoming data to be validated, and then checks the result of the validation. In this example, there is an SQL injection attack in the name field, so validation will fail and the database is protected.

Zod, React Hook Form, and Contentful

The Contentful® Composable Content Platform lets you define your content model, including content types made up of text, images, videos, and other media, manage it in our creator-friendly user interface, and then publish using REST and GraphQL delivered from our high-speed network.

By integrating Contentful with React Hook Form and Zod for validation, you can ensure all data sent and received is clean, validated, and consistent. This combination significantly reduces the risk of runtime errors caused by invalid data, and gives your users the best possible experience when using your React apps.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Meet the authors

David Fateh

David Fateh

Software Engineer

Contentful

David Fateh is a software engineer with a penchant for web development. He helped build the Contentful App Framework and now works with developers that want to take advantage of it.

Related articles

If you're feeling the limitations of traditional CMSes like WordPress and Drupal, it's time to look at the headless CMS and the composable content platform.
Guides

What are the benefits of a headless CMS versus a traditional CMS?

June 22, 2023

Ready to deploy Content Source Maps in a Next.js project? Enhance live previews with automatic links between displayed content and corresponding fields in Contentful.
Guides

Effortless automatic content linking in Next.js using Content Source Maps

September 30, 2024

Let's explore how to use Swift 5 to process JSON data, and learn how to make requests to Contentful APIs and deserialize the data to render the results.
Guides

Deserializing JSON in Swift 5 and Contentful

November 24, 2022

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started