Carlos Dubón
BlogCreatingContactUsesResume
HomeBlogCreatingContactUsesResume

Oct 21, 2024

Using Zod with react-hook-form and TypeScript in React

reacttypescript
Blog post image

If your app interacts with an API, it's crucial to validate inputs before making any requests. Imagine a sign-up form with fields for email and password. If the user types "HelloWorld" in the email field, that’s clearly not an email.

While your API might catch it and return an error like "The email must be valid," it’s more efficient to validate on both the frontend and backend. This saves time by catching errors before making unnecessary requests. So, let’s dive into how to set up validation using Zod and React Hook Form.

#Step 1: Install Zod and React Hook Form

First, install the necessary packages:

terminal
yarn add react-hook-form zod @hookform/resolvers

#Step 2: Define a validation schema with Zod

Now, we’ll create a schema to define our form’s structure and validation rules:

src/components/MyForm.tsx
import { z } from "zod";
 
const SignUpSchema = z.object({
  email: z.string().email(),
  password: z.string().min(3).max(20),
});
 
type SignUpSchemaType = z.infer<typeof SignUpSchema>;

Here, we’re saying the email must be a string and a valid email format, and password must be a string between 3 and 20 characters.

#Step 3: Set up the form component

Let’s create a basic form with fields for email and password:

export default function MyForm() {
  return (
    <form className="form">
      <input className="input" placeholder="email" />
      <input className="input" placeholder="password" />
      <button type="submit">Submit</button>
    </form>
  );
}

#Step 4: Add React Hook Form

Now we’ll integrate useForm from React Hook Form:

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
 
export default function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SignUpSchemaType>({
    resolver: zodResolver(SignUpSchema),
  });
 
  return (
    <form className="form">
      <input className="input" placeholder="email" {...register("email")} />
      <input
        className="input"
        placeholder="password"
        {...register("password")}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

We’ve added useForm to handle form validation using zodResolver to connect our Zod schema.

#Step 5: Display validation errors

Next, we’ll show error messages below the inputs if validation fails. For example, if someone enters "HelloWorld" as their email, it’ll trigger an error:

return (
  <form className="form">
    <input className="input" placeholder="email" {...register("email")} />
    {errors.email && <span>{errors.email.message}</span>}
 
    <input className="input" placeholder="password" {...register("password")} />
    {errors.password && <span>{errors.password.message}</span>}
 
    <button type="submit">Submit</button>
  </form>
);

Now, when there’s an error in either the email or password field, the relevant error message will display.

#Step 6: Handling form submission

Finally, we handle form submission with validation. When the form passes all checks, the onSubmit function will execute:

const onSubmit: SubmitHandler<SignUpSchemaType> = (data) => {
  console.log(data);
};
 
<form onSubmit={handleSubmit(onSubmit)} className="form">
  {/* form fields */}
</form>;

#Full example

Here’s the complete code for reference:

src/components/MyForm.tsx
import { z } from "zod";
import { useForm, SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
 
const SignUpSchema = z.object({
  email: z.string().email(),
  password: z.string().min(3).max(20),
});
 
type SignUpSchemaType = z.infer<typeof SignUpSchema>;
 
export default function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SignUpSchemaType>({
    resolver: zodResolver(SignUpSchema),
  });
 
  const onSubmit: SubmitHandler<SignUpSchemaType> = (data) => {
    console.log(data);
  };
 
  return (
    <form onSubmit={handleSubmit(onSubmit)} className="form">
      <input className="input" placeholder="email" {...register("email")} />
      {errors.email && <span>{errors.email.message}</span>}
 
      <input
        className="input"
        placeholder="password"
        {...register("password")}
      />
      {errors.password && <span>{errors.password.message}</span>}
 
      <button type="submit">Submit</button>
    </form>
  );
}

#Conclusion

That’s it! With Zod and React Hook Form, you can easily set up form validation in your React applications. For more advanced features, check out their documentation. Thanks for reading!

Enjoy my content? Stay updated with my newsletter.

No spam, just useful updates. Read privacy policy.
Carlos Dubón
Carlos Dubón
Software Engineer
© 2024-present Carlos Dubón. All Rights Reserved.

General

  • Home
  • Creating
  • Contact
  • Resume

Writing

  • Blog
  • Snippets
  • Uses

What I’m listening to

Not playing
Spotify