Check out our talk at Remix Conf!

The full-stack form library
for Remix and React Router

import { z } from 'zod'
import { makeDomainFunction } from 'domain-functions'
// Learn how to create these files on "Get Started" ๐Ÿ‘‡๐Ÿฝ
import { formAction } from '~/form-action'
import { Form } from '~/form'

const schema = z.object({
  firstName: z.string().min(1),
  email: z.string().min(1).email(),
  howYouFoundOutAboutUs: z.enum(['fromAFriend', 'google']),
})

const mutation = makeDomainFunction(schema)(async (values) => values)

export const action: ActionFunction = async ({ request }) =>
  formAction({
    request,
    schema,
    mutation,
    successPath: '/success',
  })

export default () => <Form schema={schema} />

This tiny code creates the form below ๐Ÿ‘‡๐Ÿฝ

E2E type-safe, with client + server validations, a11y, pending UI, and focus management

(Go ahead, try it with JS disabled as well ๐Ÿ˜‰)

100% customizable UI

Customize everything without losing our accessible defaults.

Single source of truth

Write your schema once and derive everything else from it.

Bulletproof DX

End-to-end typed to your schema. Goodbye typos, hello autocomplete!

Server-side wiring

Perform secure server-side mutations with zero boilerplate.

Full-stack validation

Validate everything both on the client and the server.

Focus management

Focus on the first field with error even for server-side failures.