@conform-to/zod

Conform helpers for integrating with Zod

getFieldsetConstraint

This tries to infer constraint of each field based on the zod schema. This is useful for:

  1. Making it easy to style input using CSS, e.g. :required
  2. Having some basic validation working before/without JS
1import { useForm } from '@conform-to/react';
2import { getFieldsetConstraint } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6  email: z.string({ required_error: 'Email is required' }),
7  password: z.string({ required_error: 'Password is required' }),
8});
9
10function Example() {
11  const [form, { email, password }] = useForm({
12    constraint: getFieldsetConstraint(schema),
13  });
14
15  // ...
16}
17

parse

It parses the formData and returns a submission result with the validation error. If no error is found, the parsed data will also be populated as submission.value.

1import { useForm } from '@conform-to/react';
2import { parse } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6  email: z.string({ required_error: 'Email is required' }),
7  password: z.string({ required_error: 'Password is required' }),
8});
9
10function ExampleForm() {
11  const [form, { email, password }] = useForm({
12    onValidate({ formData }) {
13      return parse(formData, {
14        schema,
15      });
16    },
17  });
18
19  // ...
20}
21

Or when parsing the formData on server side (e.g. Remix):

1import { useForm } from '@conform-to/react';
2import { parse } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6  // Define the schema with zod
7});
8
9export async function action({ request }) {
10  const formData = await request.formData();
11  const submission = await parse(formData, {
12    // If you need extra validation on server side
13    schema: schema.refine(/* ... */),
14
15    // If the schema definition includes async validation
16    async: true,
17  });
18
19  if (!submission.value || submission.intent !== 'submit') {
20    return submission;
21  }
22
23  // ...
24}
25

refine

A helper function to define a custom constraint on a superRefine check. This is mainly used to setup async validation.

1import { refine } from '@conform-to/zod';
2
3function createSchema(
4  intent: string,
5  constraints: {
6    // The validation will only be implemented on server side
7    isEmailUnique?: (email) => Promise<boolean>;
8  } = {},
9) {
10  return z.object({
11    email: z
12      .string({ required_error: 'Email is required' })
13      .email('Email is invalid')
14      // Pipe the schema so it runs only if the username is valid
15      .pipe(
16        z.string().superRefine((email, ctx) =>
17          refine(ctx, {
18            // It fallbacks to server validation when it returns an undefined value
19            validate: () => constraints.isEmailUnique?.(email),
20            // This makes it validate only when the user is submitting the form
21            // or updating the email
22            when: intent === 'submit' || intent === 'validate/email',
23            message: 'Email is already used',
24          }),
25        ),
26      ),
27
28    // ...
29  });
30}
31