Check out our talk at Remix Conf!


In this example, all sorts of number schemas are validated on the client and on the server.

const schema = z.object({
  mandatory: z.number(),
  optional: z.number().optional(),
  nullable: z.number().nullable(),
  defaultRandom: z.number().default(Math.random),
  greaterThan: z.number().gt(5),
  greaterThanOrEqualTo: z.number().gte(10),
  lowerThan: z.number().lt(5),
  lowerThanOrEqualTo: z.number().lte(10),
  integer: z.number().int(),

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

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

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