CONFORM latest release GitHub license

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

Highlights

  • Focused on progressive enhancement by default
  • Simplifed integration through event delegation
  • Server first validation with Zod / Yup schema support
  • Field name inference with type checking
  • 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 } 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.string().min(1, 'Email is required').email('Email is invalid'),
10  password: z.string().min(1, 'Password is required'),
11});
12
13export async function action({ request }: ActionArgs) {
14  const formData = await request.formData();
15  const submission = parse(formData, { schema });
16
17  if (!submission.value || submission.intent !== 'submit') {
18    return json(submission, { status: 400 });
19  }
20
21  return await authenticate(submission.value);
22}
23
24export default function LoginForm() {
25  const lastSubmission = useActionData<typeof action>();
26  const [form, { email, password }] = useForm({
27    lastSubmission,
28    onValidate({ formData }) {
29      return parse(formData, { schema });
30    },
31  });
32
33  return (
34    <Form method="post" {...form.props}>
35      <div>
36        <label>Email</label>
37        <input type="email" name={email.name} />
38        <div>{email.error}</div>
39      </div>
40      <div>
41        <label>Password</label>
42        <input type="password" name={password.name} />
43        <div>{password.error}</div>
44      </div>
45      <button>Login</button>
46    </Form>
47  );
48}
49