Integration / Remix

Remix

Here is a login form example integrating with Remix. You can find the full example here.

1import { getFormProps, getInputProps, useForm } from '@conform-to/react';
2import { parseWithZod } from '@conform-to/zod';
3import type { ActionArgs } from '@remix-run/node';
4import { json, redirect } from '@remix-run/node';
5import { Form, useActionData } from '@remix-run/react';
6import { z } from 'zod';
7
8const schema = z.object({
9  email: z.string().email(),
10  password: z.string(),
11  remember: z.boolean().optional(),
12});
13
14export async function action({ request }: ActionArgs) {
15  const formData = await request.formData();
16  const submission = parseWithZod(formData, { schema });
17
18  if (submission.status !== 'success') {
19    return json(submission.reply());
20  }
21
22  // ...
23}
24
25export default function Login() {
26  // Last submission returned by the server
27  const lastResult = useActionData<typeof action>();
28  const [form, fields] = useForm({
29    // Sync the result of last submission
30    lastResult,
31
32    // Reuse the validation logic on the client
33    onValidate({ formData }) {
34      return parseWithZod(formData, { schema });
35    },
36
37    // Validate the form on blur event triggered
38    shouldValidate: 'onBlur',
39  });
40
41  return (
42    <Form method="post" id={form.id} onSubmit={form.onSubmit}>
43      <div>
44        <label>Email</label>
45        <input type="email" name={fields.email.name} />
46        <div>{fields.email.errors}</div>
47      </div>
48      <div>
49        <label>Password</label>
50        <input type="password" name={fields.password.name} />
51        <div>{fields.password.errors}</div>
52      </div>
53      <label>
54        <div>
55          <span>Remember me</span>
56          <input type="checkbox" name={fields.remember.name} />
57        </div>
58      </label>
59      <hr />
60      <button>Login</button>
61    </Form>
62  );
63}