Skip to main content

Introduction

A form schema is a JSON object that fully describes the structure, behavior, and output of a dynamic form. Instead of building UIs by hand, you define what the form should contain — inputs, sections, logic — and how it should behave — conditions, validations, defaults — in a single configuration.

Instead of coding the UI manually, you describe what the form contains (fields, groups, modals…) and how it behaves (conditions, validations, default values…) — all from a single configuration file.

This approach makes it possible to build advanced forms without writing any frontend code, making it ideal for low-code or no-code platforms.

Why use a schema? • Design complex forms without Frontend development knowledge • Keep business logic and layout outside of your app code. • Reuse, version, and maintain forms like any other config.

The app reads your schema and renders the appropriate UI components. It also computes the output object that mirrors your structure, taking into account visibility rules, validations, default values, and user interactions.

In this guide, you’ll learn:

  • How schemas are structured
  • What components are available (text fields, selects, groups, modals, etc.)
  • How to control visibility, read-only states, and validations
  • How to define logic that reacts to user input
  • How to structure the resulting data

Your entire form can be expressed declaratively, without writing any imperative UI code.

Schema overview

The schema is a plain JSON object. It doesn’t require a fixed root structure — it can start with a container (section, group, modal) or directly with form components.

What matters is that the schema is valid JSON and follows the documented format: each node must define its component or type, and use the appropriate structure (properties, label, validations, etc.) based on its role.

Each node represents a component — whether it’s an input, a container, or a layout element — and supports a consistent set of keys that define its type, behavior, and visibility.

Root structure

{
"type": "section",
"properties": {
"email": { "component": "text", "label": "Email" },
"details": {
"type": "group",
"properties": {
"first_name": { "component": "text" },
"last_name": { "component": "text" }
}
}
}
}
  • The root object has a type or component (section, group, etc.).
  • All child elements are listed under properties (object of key/component pairs).
  • Every input has a component, and optionally a name, label, and more.

⚠️ Structural components like section and group do not support label, except for modal, which has its own header rendering logic.

Common keys

KeyRequiredDescription
type or componentThe type of component to render. Aliases allowed.
label❌ (not on structure)Display label shown to the user. Only applies to inputs and modals.
name✅ (for inputs)Used as the key in the output object.
properties✅ (for containers)Dictionary of nested components.
visibleBoolean or array of conditions.
readOnly / disabledBoolean or condition array.
validationsList of validation rules (string or object).
defaultInitial value.
onValueChangeReactions when value changes.

See the Common properties page for complete details.

Evaluation order

When the schema is parsed, this is the evaluation flow for each node:

  1. Defaults are applied if no value is provided.
  2. Visibility is checked. If visible === false, the field is not rendered.
  3. If hidden and keepValueIfHidden !== true, its value is dropped.
  4. ReadOnly / Disabled states are computed.
  5. If visible and editable, user interactions are allowed.
  6. onValueChange triggers may update other fields.
  7. Validations are applied before submission.

Key rules

  • Components inside a group write at the same level in the output object.
  • Components inside a section or modal may be prefixed depending on your use.
  • All keys must be unique within the same scope (i.e. same properties level).
  • You can nest groups and sections as deeply as needed.
  • Each node should be explicit about its type (type, component, or both).

Next: learn more about each component type and the properties they support → Common properties.