Zod
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
Installation
npm i @sjsf/zod-validator zod zod-to-json-schema json-schema-to-zod
yarn add @sjsf/zod-validator zod zod-to-json-schema json-schema-to-zod
pnpm add @sjsf/zod-validator zod zod-to-json-schema json-schema-to-zod
bun add @sjsf/zod-validator zod zod-to-json-schema json-schema-to-zod
References:
Example
<script lang="ts"> import { RawForm, ON_INPUT, type Schema } from "@sjsf/form"; import { createValidator } from "@sjsf/zod-validator"; import { zodToJsonSchema } from "zod-to-json-schema"; import { z } from "zod";
import { createCustomForm } from "@/components/custom-form";
import { initialValue, uiSchema } from "./_shared";
const schema = z.object({ id: z .string() .regex(new RegExp("\\d+"), "Must be a number") .min(8) .optional(), active: z.boolean().optional(), skills: z.array(z.string().min(5)).min(4).optional(), multipleChoicesList: z .array(z.enum(["foo", "bar", "fuzz"])) .max(2) .optional(), });
type Value = z.infer<typeof schema>;
const validator = createValidator({ schema, uiSchema });
const form = createCustomForm({ schema: zodToJsonSchema(schema, { errorMessages: true }) as Schema, uiSchema, validator, fieldsValidationMode: ON_INPUT, initialValue: initialValue as Value, });</script>
<RawForm {form} novalidate />
<pre>{JSON.stringify(form.value, null, 2)}</pre>
import type { Schema, UiSchema } from "@sjsf/form";
export const schema: Schema = { type: "object", properties: { id: { type: "string", minLength: 8, pattern: "\\d+", }, active: { type: "boolean", }, skills: { type: "array", minItems: 4, items: { type: "string", minLength: 5, }, }, multipleChoicesList: { type: "array", maxItems: 2, items: { type: "string", enum: ["foo", "bar", "fuzz"], }, }, },};
export const uiSchema: UiSchema = { id: { "ui:options": { title: "Identifier", }, }, active: { "ui:options": { title: "Active", }, }, multipleChoicesList: { "ui:options": { title: "Pick max two items", }, },};
export const initialValue = { id: "Invalid", skills: ["karate", "budo", "aikido"], multipleChoicesList: ["foo", "bar", "fuzz"],};
Caveats
-
If you using this library only for full form validation (without fields validation mode) and your form does not have and
oneOf
,anyOf
,dependencies
if
keywords or recursive references, you can use this library pretty safely. -
If you are using fields validation mode then starting from this point internally we start to use
json-schema-to-zod
. So first of all, please read this warning about using this library at runtime. However, I believe you are still safe as only small leafy bits of the circuit are transformed with this approach. -
If you use any conditional keyword or recursive references it means with a high probability something can go wrong. If you have problems with this approach, try using zod with a different validator using the
augment
submodule. So in this case zod validator will be used only for full form validation.
import { createValidator } from "@sjsf/other-validator";import { withZod } from "@sjsf/zod-integration/augment";
const validator = withZod(createValidator(), { schema });
Async validation
This validator supports async validation but only for the full form validation.
import { createValidator } from "@sjsf/zod-validator";
const validator = createValidator({ async: true, schema,});
API
import type { ZodSchema } from "zod";import type { Schema, UiSchemaRoot, Config } from "@sjsf/form";import type { Validator } from "@sjsf/zod-validator";
interface ValidatorOptions<Async extends boolean> { async: Async; schema: ZodSchema; /** @default {} */ uiSchema?: UiSchemaRoot; /** @default DEFAULT_ID_PREFIX */ idPrefix?: string; /** @default DEFAULT_ID_SEPARATOR */ idSeparator?: string; /** @default makeZodSchemaFactory() */ zodSchemaFactory?: (schema: Schema, rootSchema: Schema) => ZodSchema; /** @default makeFieldZodSchemaFactory() */ fieldZodSchemaFactory?: (config: Config) => ZodSchema;}
type ValidatorFactoryOptions<Async extends boolean> = Omit< ValidatorOptions<Async>, "async"> & { /** @default false */ async?: Async;};
function createValidator<Async extends boolean = false>( options?: ValidatorFactoryOptions<Async>): Validator<Async>;