Skip to content

Components · Forms

SchemaDrivenForm

A form rendered from a field schema: seven field types, required and validation rules, sections and conditional fields.

@rookcom/monarch-react/patternsComponent

Booking form with sections and a conditional field

Your details
Your visit

Tell us what to prepare.

One day before.

Usage examples

Integration settings with a Cancel action

Read-only

Purpose

Renders forms whose fields are data rather than code: booking and intake forms people build, custom fields, integration settings defined by a provider list. The product owns the schema and what happens on submit. Import from @rookcom/monarch-react/patterns.

Use when

  • The fields come from configuration or the server (custom fields, form builders, integration settings).
  • The same fields must render identically in a builder preview and the live form.

Avoid when

  • A fixed form written once: compose Field, Input and friends directly, so each field can be tuned.
  • Settings that save as each switch flips: use SwitchSettingsList.

Design principles

  • Small and typed: a discriminated union of seven field types, no form library, no runtime schema parser.
  • The schema is data: conditions such as { field: "topic", equals: "other" } can come from JSON; a function is allowed when data cannot say it.
  • Built on Field, so every label, help text and error is wired the same way as hand-written Monarch forms.
  • Errors appear when a field is left or on submit, never while someone is still typing their first character.
  • Hidden fields are neither validated nor submitted, so a condition can never block the form invisibly.

API reference

import { SchemaDrivenForm, formatSchemaValue, isSchemaFieldVisible, schemaDefaultValues, validateSchemaField, validateSchemaForm } from '@rookcom/monarch-react/patterns';
ExportKindRenderingRoot class
SchemaDrivenFormcomponentclient.mn-schema-driven-form
formatSchemaValueutilityclient–
isSchemaFieldVisibleutilityclient–
schemaDefaultValuesutilityclient–
validateSchemaFieldutilityclient–
validateSchemaFormutilityclient–

Renders a <form noValidate> (ref); sections are <fieldset> with a <legend>. Each field wrapper has data-schema-field and data-type.

Fields: text (with inputType email, url, tel or password), textarea, number, select, checkbox, switch and date. Values are strings, numbers, booleans, YYYY-MM-DD strings or null.

Rules: required, minLength, maxLength, pattern (a string, anchored), min, max, integer and a validate(value, values) function.

Helpers: schemaDefaultValues, isSchemaFieldVisible, validateSchemaField, validateSchemaForm (reuse them on the server) and formatSchemaValue for read-only display.

Generated from the TypeScript declarations of packages/react/src/components/forms/schema-driven-form.

Properties

SchemaDrivenForm

Renders a form from a field schema: text, number, select, checkbox, switch, date and textarea fields, with required and length, pattern and range rules, titled sections and conditional visibility. Built on Field, so labels, help and errors are wired for assistive technology. On submit it validates, focuses the first invalid field, and passes the visible values.

PropTypeDescription
schema requiredSchemaDrivenFormSchemaThe fields and sections to render, in order.
classNamestring
defaultValuesSchemaDrivenFormValuesInitial values (uncontrolled). Default: each field's `defaultValue`.
disabledbooleanDisables every field and the submit button.
errorsRecord<string, ReactNode>Errors from the product, such as the server's, keyed by field name. Shown with the built-in ones.
idstring
localestringBCP 47 locale for dates and numbers. Pass it for server rendering.
messagesPartial<SchemaDrivenFormMessages>Override built-in strings.
onSubmit((values: SchemaDrivenFormValues) => unknown)Called with the visible fields' values once they are valid. Return a promise to show the submit button busy; reject with an Error to show its message above the buttons.
onValuesChange((values: SchemaDrivenFormValues, name: string) => void)Called on every change with all values and the name of the field that changed.
readOnlybooleanShow values as text in a description list instead of controls (no `<form>`, so no ref).
secondaryActionsReactNodeButtons after submit, such as Cancel.
submitLabelReactNodeLabel of the submit button, or `null` for no button (submit from outside with `form=`).
validateOn"submit" | "blur"When errors first show: when a field loses focus (`blur`, default) or only on submit.
valuesSchemaDrivenFormValuesValues (controlled), keyed by field name. Missing keys use the field's empty value.

Variants

PropValuesDescription
validateOn'blur''submit'blur (default) shows a field’s error once it loses focus; submit waits for the first submit.
readOnly'false''true'true shows the visible values as a description list, formatted with formatSchemaValue.
submitLabel'“Save” (default)''any text''null'null hides the button, for a submit button elsewhere (form attribute) or a dialog footer.

States

StateExposed asBehaviour
Invalidaria-invalid on the controlError under the field, linked by aria-describedby.
Requiredaria-requiredAsterisk after the label.
Hidden–A field or section whose visibleWhen does not hold is not rendered.
Submittingaria-busy on the form and buttonFields disabled while the onSubmit promise runs.
Submit failedrole="alert"The rejection’s message above the buttons.
Disabled–Every field and the submit button disabled.
Read-onlydata-readonlyA description list instead of controls.

Interaction behaviour

  • Each change calls onValuesChange(values, name); conditional fields appear and disappear immediately.
  • Submit validates every visible field; if any fail, focus moves to the first invalid one and onSubmit is not called.
  • Valid submits call onSubmit with only the visible fields’ values. Return a promise to show the busy state; reject to show an error.
  • Number fields keep partial text such as “-” or “1.” while the value stays a number.
  • Product errors (for example from the server) go in errors by field name and show at once.

Keyboard support

KeysAction
Tab / Shift+TabMoves between fields and buttons in schema order.
EnterIn a single-line field, submits the form.
SpaceToggles a checkbox or switch.

The date field adds DatePicker’s calendar keys; selects use the platform’s keys.

Accessibility

Role
form (when named) containing groups
Accessible name
Give the form an aria-label or aria-labelledby; sections are named by their legend.
  • Labels, descriptions and errors are wired by Field; required fields have aria-required and a visual asterisk.
  • Section descriptions are linked to their fieldset with aria-describedby.
  • Errors are announced politely when they appear; a failed submit is an alert.
  • Focus moves to the first invalid field on submit, so keyboard and screen-reader users land on the problem.
  • Verified with axe in jsdom and in Chromium, Firefox and WebKit on /components/schema-driven-form.

Responsive behaviour

  • One column at every width; controls fill the form’s width, number fields are capped at 12rem.
  • The read-only list puts labels beside values, and stacks them under 30rem.

Theme support

  • Monarch tokens only; sections are separated by --mn-color-border-subtle.
  • Every control is a Monarch control, so light, dark, high-contrast and product accents apply unchanged.

Do and don't

Do

  • Validate again on the server with the same schema (validateSchemaForm runs anywhere).
  • Write patternMessage whenever you use pattern, with an example of the expected format.
  • Pass locale when rendering on the server, so dates and numbers match the client.

Don't

  • Do not hide a required field behind a condition and expect it to be filled; hidden fields are skipped.
  • Do not use a switch for consent; use a required checkbox.
  • Do not reach for this for one fixed form; hand-written Fields are easier to tune.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsButton, Alert, Checkbox, Field, Switch, Input, DatePicker

Testing coverage

  • schemaDefaultValues, data and function conditions with isSchemaFieldVisible.
  • validateSchemaForm: required, must-accept, pattern, integer, maxLength, max and number rules; hidden fields skipped.
  • formatSchemaValue: option labels, Yes/No, empty, locale numbers and dates.
  • Labelled controls of every type in named fieldsets with descriptions; conditional field hidden; axe.
  • Error on blur, cleared by typing; conditional field appears; axe.
  • Submit validates, focuses the first invalid field, then submits only visible values.
  • Number text keeps partial input and reports text that is not a number.
  • Controlled values; product errors; rejected submit alert; secondary actions.
  • Busy while submitting; disabled; no submit button with submitLabel={null}.
  • Read-only description list; axe; translated messages; renders on the server.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/schema-driven-form; Cross-browser axe: /components/schema-driven-form

Tests: packages/react/src/components/forms/schema-driven-form