Skip to content

Multi-Step Forms

Split a form into steps. The renderer handles navigation, progress, and per-step validation.

Basic multi-step

Use steps instead of fields in the definition:

json
{
  "id": "account-setup",
  "title": "Account Setup",
  "submit": { "label": "Create Account" },
  "steps": [
    {
      "id": "personal",
      "title": "Personal Information",
      "description": "Tell us about yourself",
      "fields": [
        { "key": "name", "type": "text", "label": "Full name", "validation": { "required": true } },
        { "key": "email", "type": "email", "label": "Email", "validation": { "required": true } }
      ]
    },
    {
      "id": "address",
      "title": "Address",
      "fields": [
        { "key": "street", "type": "text", "label": "Street", "validation": { "required": true } },
        { "key": "city", "type": "text", "label": "City", "validation": { "required": true } }
      ]
    },
    {
      "id": "confirm",
      "title": "Confirm",
      "fields": [
        { "key": "terms", "type": "checkbox", "label": "I accept the terms", "validation": { "required": "You must accept" } }
      ]
    }
  ]
}
  • Continue validates the current step. If valid, moves to the next visible step. If not, shows errors.
  • Back goes to the previous visible step. No validation.
  • Submit replaces Continue on the last visible step.
  • Progress bar shows "Step N of M" based on visible steps.

Custom labels per step

Override the Continue or Back button label on any step:

json
{
  "id": "review",
  "title": "Review & Send",
  "back": { "label": "Edit Details" },
  "fields": [...]
}

Set back to false to hide the Back button on a step:

json
{
  "id": "first-step",
  "title": "Welcome",
  "back": false,
  "fields": [...]
}

variant and action are available as metadata to custom action components. The built-in adapters use the resolved labels for step navigation.

Conditional steps

Steps support show/showAny conditions, same as fields. Hidden steps are skipped, and their fields are not validated or submitted.

json
{
  "id": "business-info",
  "title": "Business Details",
  "show": [{ "field": "accountType", "eq": "business" }],
  "fields": [
    { "key": "companyName", "type": "text", "label": "Company name" },
    { "key": "taxId", "type": "text", "label": "Tax ID" }
  ]
}

When the user picks "personal" instead of "business", this step vanishes. The progress bar updates from "Step 2 of 4" to "Step 2 of 3".

Step change callback

vue
<template>
  <FormRenderer
    :definition="definition"
    @step-change="(stepId, direction) => console.log(stepId, direction)"
    @submit="onSubmit"
  />
</template>
tsx
<FormRenderer
  definition={definition}
  onStepChange={(stepId, direction) => console.log(stepId, direction)}
  onSubmit={handleSubmit}
/>

direction is 'next' or 'back'.

Async step validation

Need to check something on the server before advancing? See the Async Step Validation guide.

getSubmitValues

On submit, all visible fields across all visible steps are returned. Fields in hidden steps are excluded.

Next steps