CONFORM latest release GitHub license

A progressive enhancement first form validation library for Remix and React Router

Highlights

  • Progressive enhancement first APIs
  • Automatic type coercion with Zod
  • Simplifed integration through event delegation
  • Field name inference
  • Focus management
  • Accessibility support
  • About 5kb compressed

Quick Start

Here is an example built with Remix:

1import { useForm } from '@conform-to/react';
2import { parse } from '@conform-to/zod';
3import { Form, useActionData } from '@remix-run/react';
4import { json } from '@remix-run/node';
5import { z } from 'zod';
6import { authenticate } from '~/auth';
7
8const schema = z.object({
9  email: z
10    .string({ required_error: 'Email is required' })
11    .email('Email is invalid'),
12  password: z.string({ required_error: 'Password is required' }),
13});
14
15export async function action({ request }: ActionArgs) {
16  const formData = await request.formData();
17  const submission = parse(formData, { schema });
18
19  if (!submission.value || submission.intent !== 'submit') {
20    return json(submission);
21  }
22
23  return await authenticate(submission.value);
24}
25
26export default function LoginForm() {
27  const lastSubmission = useActionData<typeof action>();
28  const [form, { email, password }] = useForm({
29    lastSubmission,
30    onValidate({ formData }) {
31      return parse(formData, { schema });
32    },
33  });
34
35  return (
36    <Form method="post" {...form.props}>
37      <div>
38        <label>Email</label>
39        <input type="email" name={email.name} />
40        <div>{email.error}</div>
41      </div>
42      <div>
43        <label>Password</label>
44        <input type="password" name={password.name} />
45        <div>{password.error}</div>
46      </div>
47      <button>Login</button>
48    </Form>
49  );
50}
51