Skip to main content

Multi-Step & Conversational Forms

Core Forms supports splitting long forms into multiple steps with progress indicators, step-by-step navigation, and per-step validation. You can also use conversational mode for a focused, one-question-at-a-time experience.

Schema Layout Types

Set the layout type in the form schema to enable multi-step or conversational rendering:

{
  "layout": {
    "type": "multi-step"
  }
}

Or for conversational mode:

{
  "layout": {
    "type": "conversational"
  }
}

Defining Steps

Option 1: Group Property on Fields

Assign a group property to each field in your schema. Fields sharing the same group value are rendered together in a single step.

{
  "fields": [
    { "name": "first_name", "type": "text", "label": "First Name", "group": "personal" },
    { "name": "last_name", "type": "text", "label": "Last Name", "group": "personal" },
    { "name": "email", "type": "email", "label": "Email", "group": "contact" },
    { "name": "phone", "type": "tel", "label": "Phone", "group": "contact" },
    { "name": "message", "type": "textarea", "label": "Message", "group": "details" }
  ]
}

This produces three steps: personal, contact, and details.

Option 2: Explicit Steps Array

Define steps explicitly with layout.steps for full control over step titles and field ordering:

{
  "layout": {
    "type": "multi-step",
    "steps": [
      { "id": "personal", "title": "Your Info", "fields": ["first_name", "last_name"] },
      { "id": "contact", "title": "Contact", "fields": ["email", "phone"] },
      { "id": "details", "title": "Message", "fields": ["message"] }
    ]
  }
}

Generated HTML Structure

Core Forms renders the following markup for multi-step forms:

<form class="cf-form cf-multi-step" data-layout="multi-step">
  <!-- Progress bar -->
  <div class="cf-progress" role="progressbar" aria-valuenow="1" aria-valuemin="1" aria-valuemax="3">
    <div class="cf-progress-bar" style="width: 33.33%"></div>
    <ol class="cf-step-indicators">
      <li class="cf-step cf-step-active" data-step="1">
        <span class="cf-step-number">1</span>
        <span class="cf-step-title">Your Info</span>
      </li>
      <li class="cf-step" data-step="2">
        <span class="cf-step-number">2</span>
        <span class="cf-step-title">Contact</span>
      </li>
      <li class="cf-step" data-step="3">
        <span class="cf-step-number">3</span>
        <span class="cf-step-title">Message</span>
      </li>
    </ol>
  </div>

  <!-- Step panels -->
  <div class="cf-step-panel cf-step-panel-active" data-step="1">
    <!-- Fields for step 1 -->
  </div>
  <div class="cf-step-panel" data-step="2" hidden>
    <!-- Fields for step 2 -->
  </div>
  <div class="cf-step-panel" data-step="3" hidden>
    <!-- Fields for step 3 -->
  </div>

  <!-- Hidden input tracking current step -->
  <input type="hidden" name="_cf_current_step" value="1">

  <!-- Step navigation -->
  <div class="cf-step-nav">
    <button type="button" class="cf-step-prev" disabled>Previous</button>
    <button type="button" class="cf-step-next">Next</button>
    <button type="submit" class="cf-step-submit" hidden>Submit</button>
  </div>
</form>

Progress Indicators

The .cf-progress container renders both a visual progress bar and numbered step indicators. The progress bar width updates automatically as the user advances:

Step 1 of 3 → width: 33.33%
Step 2 of 3 → width: 66.66%
Step 3 of 3 → width: 100%

Completed steps receive the cf-step-complete class. The active step has cf-step-active.

Step Navigation

Navigation buttons appear in the .cf-step-nav container:

  • Previous button is disabled on the first step and hidden in conversational mode.
  • Next button advances to the next step after validation passes.
  • Submit button replaces Next on the final step.

The hidden _cf_current_step input is updated on every step change so the server knows which step the user reached.

Per-Step Validation

Before advancing to the next step, Core Forms validates all required fields in the current step panel. If any field fails validation:

  1. The step does not advance.
  2. Invalid fields receive the cf-invalid class with aria-invalid="true".
  3. Error messages appear below each invalid field with role="alert".
  4. Focus moves to the first invalid field.
// Validation is triggered automatically on Next click.
// Required fields, email format, min/max, and pattern are all checked per step.
// See validation.md for the full list of supported checks.

Conversational Mode

When layout.type is set to conversational, the form renders one question at a time in a centered, focused layout:

<form class="cf-form cf-conversational" data-layout="conversational">
  <div class="cf-step-panel cf-step-panel-active cf-conversational-panel" data-step="1">
    <label class="cf-conversational-label">What is your name?</label>
    <input type="text" name="name" class="cf-conversational-input" required>
  </div>
  <!-- Additional panels hidden until reached -->

  <input type="hidden" name="_cf_current_step" value="1">

  <div class="cf-step-nav cf-conversational-nav">
    <button type="button" class="cf-step-next">Continue</button>
  </div>
</form>

Key differences from standard multi-step:

  • No progress bar or step indicators by default (add via filter).
  • Each panel is vertically centered on screen.
  • Enter key advances to the next question.
  • Previous button is hidden (users can click completed indicators to go back).
  • Smooth transition animations between questions.

CSS Classes Reference

Class Element Description
.cf-multi-step <form> Multi-step form wrapper
.cf-conversational <form> Conversational form wrapper
.cf-progress <div> Progress bar and indicators container
.cf-progress-bar <div> Visual progress bar fill
.cf-step-indicators <ol> Step indicator list
.cf-step <li> Individual step indicator
.cf-step-active <li> Currently active step indicator
.cf-step-complete <li> Completed step indicator
.cf-step-panel <div> Step content panel
.cf-step-panel-active <div> Visible step panel
.cf-step-nav <div> Navigation buttons container
.cf-step-prev <button> Previous step button
.cf-step-next <button> Next step button
.cf-step-submit <button> Submit button (final step)

Example: Registration Form

{
  "layout": {
    "type": "multi-step",
    "steps": [
      { "id": "account", "title": "Account", "fields": ["email", "password", "password_confirm"] },
      { "id": "profile", "title": "Profile", "fields": ["first_name", "last_name", "bio"] },
      { "id": "preferences", "title": "Preferences", "fields": ["newsletter", "terms"] }
    ]
  },
  "fields": [
    { "name": "email", "type": "email", "label": "Email", "required": true },
    { "name": "password", "type": "password", "label": "Password", "required": true, "minlength": 8 },
    { "name": "password_confirm", "type": "password", "label": "Confirm Password", "required": true },
    { "name": "first_name", "type": "text", "label": "First Name", "required": true },
    { "name": "last_name", "type": "text", "label": "Last Name", "required": true },
    { "name": "bio", "type": "textarea", "label": "About You" },
    { "name": "newsletter", "type": "checkbox", "label": "Subscribe to newsletter" },
    { "name": "terms", "type": "checkbox", "label": "I agree to the terms", "required": true }
  ]
}

This creates a three-step registration form with per-step validation ensuring required fields are filled before the user can proceed.