Skip to content
PlaygroundForm Builder

You may want to use Zod validator because:

  • You can use Zod schema as a source of truth for the form value type (z.infer).
  • This is an easy way to add custom error messages
Terminal window
npm i @sjsf/zod4-validator

Required peer dependencies: @sjsf/form@3.5.0 zod@4.1.0

<script lang="ts">
  import {
    BasicForm,
    createForm,
    getValueSnapshot,
    ON_ARRAY_CHANGE,
    ON_CHANGE,
    ON_INPUT,
  } from "@sjsf/form";
  import { adapt } from "@sjsf/zod4-validator/classic";
  import { z } from "zod";
  import { en } from "zod/locales";

  import * as defaults from "$lib/sjsf/defaults";

  import { initialValue, uiSchema } from "../demo-schema";

  z.config(en());

  const schema = z.object({
    id: z
      .string()
      .regex(new RegExp("^\\d+$"), "Must be a number")
      .min(8)
      .optional(),
    active: z.boolean(),
    skills: z.array(z.string().min(5)).min(4).optional(),
    multipleChoicesList: z
      .array(z.enum(["foo", "bar", "fuzz"]))
      .max(2)
      .optional(),
  });

  const form = createForm({
    ...defaults,
    ...adapt(schema),
    uiSchema,
    fieldsValidationMode: ON_INPUT | ON_CHANGE | ON_ARRAY_CHANGE,
    initialValue,
  });
</script>

<BasicForm {form} novalidate />

<pre>{JSON.stringify(getValueSnapshot(form), null, 2)}</pre>

Types like z.date(), z.bigint(), z.map(), and z.set() have no JSON Schema equivalent. The adapter converts them to {} (unknown), rendering the default unknown field. You can wire custom field components via UI schema to handle these types. See the example for a working demo.

This validator supports async validation.

import { adaptAsync } from "@sjsf/zod4-validator/classic";
const { schema, validator } = adaptAsync(zodSchema);