conform icon indicating copy to clipboard operation
conform copied to clipboard

A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.

Conform · latest release GitHub license

The API is not yet stable. Expect breaking changes on minor versions before v1 (stable release).

Conform is a form validation library built on top of the Constraint Validation API.

  • Progressive enhancement: It is designed based on the specification. From reporting validity of the form to setting custom error message of each fields. If you don't like part of the solution, you can always replace it with your own one.
  • Schema-first: Define the data structure and map it to smaller individual fieldset, then compose them to make complex form. Conform aims at making easy form easy, complex form simple.
  • Framework agnostic: The DOM is the only thing it depends on. It might utilize specific features for better integration, but the core will always be based on web standard.

Example (React + Zod)

import { useFieldset, conform } from '@conform-to/react';
import { resolve, parse } from '@conform-to/zod';
import z from 'zod';

const signup = z
  .object({
    email: z.string().email(),
    password: z.string().min(8),
    confirm: z.string(),
  })
  .refine((value) => value.password === value.confirm, {
    message: 'The password do not match',
    path: ['confirm'],
  });

export default function SignupForm() {
  const [fieldsetProps, { email, password, confirm }] = useFieldset(
    resolve(signup),
  );

  return (
    <form
      onSubmit={event => {
        event.preventDefault();

        const formData = new FormData(e.currentTarget);
        const result = parse(formData, signup);

        // Send the data with fetch API
      }
    >
      <fieldset {...fieldsetProps}>
        <label>
          Email:
          <input {...conform.input(email)} />
          <p>{email.error}</p>
        </label>
        <label>
          Password:
          <input {...conform.input(password, { type: 'password' })} />
          <p>{password.error}</p>
        </label>
        <label>
          Confirm Password:
          <input {...conform.input(confirm, { type: 'password' })} />
          <p>{confirm.error}</p>
        </label>
        <button type="submit">Sign up</button>
      </fieldset>
    </form>
  );
}

More examples can be found here: Codesandbox | Stackblitz

API References

Package Description Size
@conform-to/dom A set of opinionated helpers interacting with the DOM package size
@conform-to/react View adapter for react package size
@conform-to/zod Schema resolver for zod package size