A form is data, presentation, and behavior — kept separate. Schemaform never mixes validation into your markup or hard-codes layout into your logic.
The data shape and its validation. The single source of truth for what's valid — standard JSON Schema, no proprietary dialect.
{ "type": "string", "format": "email" }
Presentation and layout. Which widget renders each field, labels, grouping, order — all without touching the data contract.
{ "widget": "select", "label": "Plan" }
Conditional behavior. Show, hide, enable, or require fields based on other answers — evaluated by the core, not your components.
{ "when": { … }, "show": ["seats"] }
Use the package directly, then browse or copy the source when your product needs to own a renderer, widget, or builder workflow.
Admins design a form in the Builder. End users fill it out in the Renderer. Both read the exact same definition envelope — there's nothing to keep in sync.
Write the form once with defineForm, field, layout helpers, and rule helpers. Schemaform returns the same persisted Form Definition envelope, but developers get field-key suggestions and fewer raw JSON pointers.
Pages and rules are inferred from the fields object, so editors can suggest keys like email or plan.
Use rule.when("plan").equals("Enterprise").require("companyName") instead of hand-writing JSONLogic.
The renderer, builder, parser, and migrations still consume the normal Form Definition shape.
Import defineForm, field, and SchemaForm from the main package. The helper returns a normal Form Definition, and the bundled renderer handles validation, rules, and submit projection.
For React teams building internal tools and SaaS product that need user-designed, dynamic forms — where the form data and the code that renders it both have to stay yours.
Install the package, render a Form Definition, and keep the option to inspect or fork the source when your product needs deeper control.