CONFORM

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