@conform-to/zod
getFieldsetConstraint
This tries to infer constraint of each field based on the zod schema. This is useful for:
- Making it easy to style input using CSS, e.g.
:required
- 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