Skip to main content

@canard/schema-form

@canard/schema-form npm versionlicense
yarn add @canard/schema-form

JSON Schema-driven React form engine with a two-layer plugin architecture: a Validator plugin for JSON Schema validation and a UI plugin for form rendering components. Declare your data shape once in JSON Schema — the library builds, validates, and manages the full form state tree automatically.

Live Demo

Try the interactive form below to see what @canard/schema-form can build from JSON Schema alone. This conference registration form demonstrates conditional fields, computed values, and 10+ input types — all driven by a single schema.

More Examples

Explore 10 interactive examples covering if/then/else, oneOf, computed values, and more in the Examples section.

UI Plugins

Each form above is rendered with the antd6-plugin. See individual plugin pages for component catalogs: antd5 | antd6 | MUI | antd-mobile

Architecture

JSON Schema


nodeFromJsonSchema() ← builds a typed node tree

├── StringNode / NumberNode / BooleanNode / NullNode (terminal)
├── ObjectNode / ArrayNode (branch)
└── VirtualNode (conditional / computed)


Plugin System
├── ValidatorPlugin ← compile(jsonSchema) → ValidateFunction
└── SchemaFormPlugin ← FormGroup / FormLabel / FormInput / FormError
+ formTypeInputDefinitions


<Form> → React component tree

Plugin System

The library ships with no default validator and no default UI components. Both must be supplied via plugins before rendering any form. Plugins are registered globally with registerPlugin() and affect every <Form> in the application.

  • Validator plugin — integrates any validation library (AJV, Zod, Yup, etc.) by implementing compile(jsonSchema).
  • UI plugin — provides FormGroup, FormLabel, FormInput, FormError renderer components and formTypeInputDefinitions for per-field input components.

Official plugin packages:

  • @canard/schema-form-ajv8-plugin — AJV 8 validator
  • @canard/schema-form-antd5-plugin — Ant Design 5 UI
  • @canard/schema-form-mui6-plugin — MUI 6 UI

Node Types

NodeSchema typesStrategy
StringNode"string"terminal
NumberNode"number", "integer"terminal
BooleanNode"boolean"terminal
NullNode"null"terminal
ObjectNode"object"branch (BranchStrategy or TerminalStrategy)
ArrayNode"array"branch (BranchStrategy or TerminalStrategy)
VirtualNodeconditional / oneOf / anyOf branchesspecial

FormTypeInput Resolution Order

When rendering a field, the library resolves which input component to use in this priority order (highest first):

  1. Direct FormTypeInput prop on Form.Group
  2. formTypeInputMap path mapping on <Form>
  3. Form-level formTypeInputDefinitions prop
  4. FormProvider formTypeInputDefinitions
  5. Plugin-provided formTypeInputDefinitions
AI Agent Reference

AI Reference

Package: @canard/schema-form v0.10.5 Purpose: JSON Schema-driven dynamic form generation for React with two-layer plugin architecture.

Plugin system

import type { SchemaFormPlugin } from '@canard/schema-form';
import type { ValidatorPlugin } from '@canard/schema-form';
import { registerPlugin } from '@canard/schema-form';

Form component

import { Form } from '@canard/schema-form';
import type { FormProps } from '@canard/schema-form';
import type { FormHandle } from '@canard/schema-form'; // ref API: submit(), reset(), validate(), getValues()
import type { FormChildrenProps } from '@canard/schema-form'; // render-prop children
import type { FormLabelProps } from '@canard/schema-form';
import type { FormErrorProps } from '@canard/schema-form';

Node types

import type { SchemaNode } from '@canard/schema-form';
import type { StringNode, NumberNode, BooleanNode, NullNode } from '@canard/schema-form'; // terminal
import type { ObjectNode, ArrayNode } from '@canard/schema-form'; // branch
import type { VirtualNode } from '@canard/schema-form'; // conditional

Enums

import { NodeState } from '@canard/schema-form';       // Initialized | Mounted | Unmounted
import { ValidationMode } from '@canard/schema-form'; // OnChange | OnBlur | OnSubmit
import { NodeEventType } from '@canard/schema-form'; // ValueChange | StateChange | ...
import { SetValueOption } from '@canard/schema-form'; // Merge | Replace

Type guards & error utilities

import { isArrayNode, isBooleanNode, isBranchNode, isNumberNode } from '@canard/schema-form';
import { isSchemaFormError, isJsonSchemaError, isUnhandledError, isValidationError } from '@canard/schema-form';
import { JSONPointer } from '@canard/schema-form';

Architecture

  • No default validator or UI — both via plugins: registerPlugin(plugin)
  • Node tree: JSON Schema → nodeFromJsonSchema() → typed node tree
  • Input resolution: Direct prop > formTypeInputMap > form-level > FormProvider > plugin