# Confirm Password using schema Zod with React Hook Form

initialize the Next.js project using this command below.

```bash
pnpm create next-app@latest my-app --typescript --tailwind --eslint
```

and fill up with the prompt with default answer like so.

```bash
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … No
```

Install the Library that we need for our form and `zod` schema validation.

```bash
pnpm i react-hook-form zod @hookform/resolvers
```

### Schema

For this tutorial we will be creating a simple register form which user will have fill up email, password and confirm their password. A `zod` schema would look like this

```typescript
// src/app/register-form/schema.ts
import z from 'zod'

export const registerSchema = z
  .object({
    email: z.string().email().min(1, { message: 'Email is Required' }),
    password: z.string().min(1, { message: 'Password is Required' }),
    confirmPassword: z
      .string()
      .min(1, { message: 'Please confirm your password' }),
  })
```

To add validation for the confirm password, there are multiple ways we can do that. In this tutorial I will use `.superRefine` from `zod` to have more freedom than normal `.refine` in defining our validation. The modified schema will look like this.

```typescript
// src/app/register-form/schema.ts
import z from 'zod'

export const registerSchema = z
  .object({
    email: z.string().email().min(1, { message: 'Email is Required' }),
    password: z.string().min(1, { message: 'Password is Required' }),
    confirmPassword: z
      .string()
      .min(1, { message: 'Please confirm your password' }),
  })
  .superRefine((val, ctx) => {
    if (val.password !== val.confirmPassword) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'Password is not the same as confirm password',
        path: ['confirmPassword'],
      })
    }
  })

export interface RegisterSchema extends z.infer<typeof registerSchema> {}
```

Take note, since we are using typescript, we need to export the schema type as well by using `z.infer` of our schema.

### Register form component

We will use the schema with the `react-hook-form` and create a simple register form with simple styling and when we finish filling up the form, it will alert the data.

```typescript
// src/app/register-form/form.tsx
'use client'

import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { registerSchema, RegisterSchema } from '@/app/register-form/schema'

export const RegisterForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<RegisterSchema>({
    resolver: zodResolver(registerSchema),
  })

  const onSubmit = handleSubmit((data) => {
    console.log(data)
    alert(JSON.stringify(data))
  })

  return (
    <form onSubmit={onSubmit} className='space-y-3'>
      <div className='flex flex-col gap-1'>
        <label htmlFor='email'>Email</label>
        <input
          id='email'
          {...register('email')}
          className='bg-transparent border py-2 px-4'
        />
        {errors.email?.message && <p>{errors.email?.message}</p>}
      </div>

      <div className='flex flex-col gap-1'>
        <label htmlFor='email'>Password</label>
        <input
          id='password'
          type='password'
          {...register('password')}
          className='bg-transparent border py-2 px-4'
        />
        {errors.password?.message && <p>{errors.password?.message}</p>}
      </div>

      <div className='flex flex-col gap-1'>
        <label htmlFor='confirmPassword'>Confirm Password</label>
        <input
          id='confirmPassword'
          type='password'
          {...register('confirmPassword')}
          className='bg-transparent border py-2 px-4'
        />
        {errors.confirmPassword?.message && (
          <p>{errors.confirmPassword?.message}</p>
        )}
      </div>

      <input type='submit' className='px-4 py-2 rounded bg-gray-500' />
    </form>
  )
}
```

now to test this we just need to replace our page component like so.

```typescript
// src/app/page.tsx
import { RegisterForm } from '@/app/register-form/form'

export default function Home() {
  return (
    <main className='flex min-h-screen flex-col items-center justify-between p-24'>
      <RegisterForm />
    </main>
  )
}
```

Now we can test this code in our `http://localhost:3000` using `pnpm dev` in our terminal.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1716615225207/7f338c24-090a-40ec-946e-67e8be91650e.png align="center")

### Additional information

Zod is powerful schema validation library that can help you type-safe your code, if you refactor your schema like changing from email to username, all your code will have an error because, you have to update them from email to username in the files that use the schema.

`.superRefine` is a powerful functions to do a custom validation as well as doing so much things like we can call an APIs for checking email uniquely or not for the validation.

Cheers!
