Using Zod with React hook form using typescript
Tags: react, nextjs, reactnative, webdev
Published: 2023-03-16 19:44:37

Hi, if your application uses some sort of API is MUST to have some validation before sending any request! for example if you have simple sign up page where you have email field and password and let's imagine if user typed something like this in the email field "HelloWorld" this is clearly isn't an email even if our API will throw some kind of error saying " the email field should be an email " the time a request go and response get back where's clearly will throw an error not worth the time in my opinion validation should be on both ways frontend and backend so what should we do? well first we need to install zod and react hook form!

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

now after installing them we make schema for our form

```
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>;
```
so now in our schema we said the email must be an string and email and our password must be a string and min 3 characters and max 20 

so now we go to our form component we create simple form

```
export default function App() {
  return (
    <form  className="form">
      <input className="input" placeholder="email" />
      <input
        className="input"
        placeholder="password"
      />
      <button type="submit">submit!</button>
    </form>
  );
}
```
now we simple add the useForm hook from the react-hook-form

```
import { useForm } from "react-hook-form";
  const {
    register,
    handleSubmit,
    formState: { errors }
  } = useForm<SignUpSchemaType>({ resolver: zodResolver(SignUpSchema) });
```
and the hook will take an object that resolver going to be from (@hookform/resolvers) which is zodResolver!

now we're ready to add connect the inputs to the hook by the register!

```
export default function App() {
  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>
  );
}

```

now whenever we type into these to fields the useForm will fire! 

so now we want to show the error message below each input to show the error if there's an error like our example if we put in the email field "HelloWorld"

here how we do it by the form state the errors!

```
 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 we have error on password or email fields will show the span


![Errors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i25di6857ye1hjimy8qt.png)


so now we need to handle when the button clicked on submit

so first we create a simple function will only fire when all validation success!

```
//we should here call like API or something...
  const onSubmit: SubmitHandler<SignUpSchemaType> = (data) => console.log(data);
```

and now we add a simple onSubmit to our form and we call handleSubmit from useForm hook like this

```
    <form onSubmit={handleSubmit(onSubmit)} className="form">

```

so now we have our validation before sending it to some API 

![Errors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i25di6857ye1hjimy8qt.png)

here's the full code

```
import "./styles.css";
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 App() {
  const {
    register,
    handleSubmit,
    formState: { errors }
  } = useForm<SignUpSchemaType>({ resolver: zodResolver(SignUpSchema) });

  //we should here call like API or something...
  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>
  );
}
```
and there's a lot to do with zod and use form hook you can look at the documentation [react hook form](https://react-hook-form.com/) [zod](https://zod.dev/) and shout-out to Austin Shelby for great [video](https://www.youtube.com/watch?v=4zt1eadehKQ&ab_channel=AustinShelby)

Thank you for giving your time to read this simple post!