✦ A decade of Canvas craft, now driven by AI, describe it, watch it build live.Start building
Bootstrap 5Forms

Bootstrap 5 Multi-Step Form

A multi-step form breaks a long or complex form into sequential sections, showing one step at a time with progress indicators between them. Bootstrap 5 does not ship a dedicated multi-step form component, but you can build one using the tab system, nav pills, cards, and utility classes combined with minimal JavaScript to control step visibility. Use this pattern whenever a form has more than five fields, collects sensitive data across logical groups (contact details, then payment, then confirmation), or when research shows users abandon single-page forms at high rates.

Primary Class

.multi-step-form

Common Use Cases

  • SaaS onboarding flow that collects account details on step 1, billing information on step 2, and team member invitations on step 3
  • Insurance quote calculator that walks users through vehicle details, driver history, and coverage preferences before showing a price
  • Event registration form that separates ticket selection, attendee details, and dietary or accessibility requirements into distinct steps
  • Job application form that groups resume upload and work history on step 1, references on step 2, and equal opportunities data on step 3

Variants & Classes

VariantDescription
Multi-Step Form DefaultStandard multi-step form with Bootstrap's default styling.
Multi-Step Form ResponsiveResponsive variant that adapts to different screen sizes.

Code Example

<div class="container py-5">
  <div class="row justify-content-center">
    <div class="col-lg-7">

      <!-- Step progress indicator -->
      <div class="d-flex justify-content-between align-items-center mb-4">
        <div class="step-item text-center">
          <div class="step-circle bg-primary text-white rounded-circle d-inline-flex align-items-center justify-content-center" style="width:40px;height:40px;" id="circle-1">1</div>
          <div class="small mt-1 fw-semibold">Account</div>
        </div>
        <div class="flex-grow-1 border-top border-2 mx-2"></div>
        <div class="step-item text-center">
          <div class="step-circle bg-secondary text-white rounded-circle d-inline-flex align-items-center justify-content-center" style="width:40px;height:40px;" id="circle-2">2</div>
          <div class="small mt-1 text-muted">Billing</div>
        </div>
        <div class="flex-grow-1 border-top border-2 mx-2"></div>
        <div class="step-item text-center">
          <div class="step-circle bg-secondary text-white rounded-circle d-inline-flex align-items-center justify-content-center" style="width:40px;height:40px;" id="circle-3">3</div>
          <div class="small mt-1 text-muted">Confirm</div>
        </div>
      </div>

      <div class="card shadow-sm border-0">
        <div class="card-body p-4">

          <!-- Step 1: Account Details -->
          <div class="step-panel" id="step-1">
            <h5 class="card-title mb-4">Create your account</h5>
            <div class="mb-3">
              <label for="fullName" class="form-label">Full name</label>
              <input type="text" class="form-control" id="fullName" placeholder="Jane Smith">
            </div>
            <div class="mb-3">
              <label for="email" class="form-label">Email address</label>
              <input type="email" class="form-control" id="email" placeholder="jane@example.com">
            </div>
            <div class="mb-4">
              <label for="password" class="form-label">Password</label>
              <input type="password" class="form-control" id="password" placeholder="Min. 8 characters">
            </div>
            <div class="d-flex justify-content-end">
              <button class="btn btn-primary" onclick="goToStep(2)">Next: Billing <i class="bi bi-arrow-right ms-1"></i></button>
            </div>
          </div>

          <!-- Step 2: Billing -->
          <div class="step-panel d-none" id="step-2">
            <h5 class="card-title mb-4">Billing information</h5>
            <div class="mb-3">
              <label for="cardName" class="form-label">Name on card</label>
              <input type="text" class="form-control" id="cardName" placeholder="Jane Smith">
            </div>
            <div class="mb-3">
              <label for="cardNumber" class="form-label">Card number</label>
              <input type="text" class="form-control" id="cardNumber" placeholder="1234 5678 9012 3456">
            </div>
            <div class="row g-3 mb-4">
              <div class="col-6">
                <label for="expiry" class="form-label">Expiry date</label>
                <input type="text" class="form-control" id="expiry" placeholder="MM / YY">
              </div>
              <div class="col-6">
                <label for="cvv" class="form-label">CVV</label>
                <input type="text" class="form-control" id="cvv" placeholder="123">
              </div>
            </div>
            <div class="d-flex justify-content-between">
              <button class="btn btn-outline-secondary" onclick="goToStep(1)"><i class="bi bi-arrow-left me-1"></i> Back</button>
              <button class="btn btn-primary" onclick="goToStep(3)">Next: Confirm <i class="bi bi-arrow-right ms-1"></i></button>
            </div>
          </div>

          <!-- Step 3: Confirm -->
          <div class="step-panel d-none" id="step-3">
            <h5 class="card-title mb-4">Review and confirm</h5>
            <div class="alert alert-light border mb-4">
              <p class="mb-1"><strong>Plan:</strong> Pro Monthly at $29/month</p>
              <p class="mb-1"><strong>Billing:</strong> Card ending in 3456</p>
              <p class="mb-0"><strong>Renews:</strong> Automatically each month. Cancel anytime.</p>
            </div>
            <div class="form-check mb-4">
              <input class="form-check-input" type="checkbox" id="termsCheck">
              <label class="form-check-label" for="termsCheck">
                I agree to the <a href="#">Terms of Service</a> and <a href="#">Privacy Policy</a>
              </label>
            </div>
            <div class="d-flex justify-content-between">
              <button class="btn btn-outline-secondary" onclick="goToStep(2)"><i class="bi bi-arrow-left me-1"></i> Back</button>
              <button class="btn btn-success" type="submit">Confirm and Subscribe</button>
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>
</div>

<script>
function goToStep(step) {
  document.querySelectorAll('.step-panel').forEach(function(panel) {
    panel.classList.add('d-none');
  });
  document.getElementById('step-' + step).classList.remove('d-none');

  [1, 2, 3].forEach(function(n) {
    var circle = document.getElementById('circle-' + n);
    if (n < step) {
      circle.classList.remove('bg-secondary');
      circle.classList.add('bg-success');
    } else if (n === step) {
      circle.classList.remove('bg-secondary', 'bg-success');
      circle.classList.add('bg-primary');
    } else {
      circle.classList.remove('bg-primary', 'bg-success');
      circle.classList.add('bg-secondary');
    }
  });
}
</script>

Live Examples

Basic Multi-Step Form

Example 1

Canvas Framework Variants

The Canvas template extends Bootstrap 5 with 1,658+ component variants. Generate any of these using Canvas Builder:

  • Canvas Builder generated multi-step form with custom colours
  • Multi-Step Form with interactive states
  • Responsive multi-step form for all screen sizes

Best Practices

Validate each step before advancing

Run Bootstrap 5 native validation (using the `was-validated` class on the form and the `required` attribute on inputs) inside your `goToStep` function before showing the next panel, so users cannot skip required fields and encounter a wall of errors at the final step.

Preserve field values when navigating backwards

Because the panels use `d-none` instead of being removed from the DOM, field values persist automatically when users click Back, which avoids one of the most frustrating multi-step form experiences without any extra state management.

Mark completed steps visually

Swap the step circle colour to `bg-success` once a step is passed (as shown in the `goToStep` function above) so users can see their progress at a glance and feel confident they are moving forward through the form.

Keep each step under five fields

If any single step requires more than five fields, consider whether you can split it further or use a collapsible accordion within that step; cognitive overload per screen undermines the entire point of breaking the form apart.

FAQ

How do I handle browser Back button navigation inside a multi-step form?
By default the browser Back button will leave the page entirely, which loses all form data. The cleanest fix is to push a new history entry with `history.pushState({step: 2}, '', '#step-2')` each time the user advances, then listen for the `popstate` event to call `goToStep(event.state.step)`. This gives users the expected Back behaviour while keeping all field values intact because the DOM is never destroyed.
Can I use Bootstrap 5 tabs or nav-pills instead of manually toggling d-none?
Yes. Bootstrap's tab component (`nav-tabs` or `nav-pills` with `data-bs-toggle='tab'`) handles panel switching for you and includes built-in ARIA attributes for accessibility. The downside is that the tab links are visible to users and they can skip steps freely. If you need enforced sequential navigation you should disable or hide the tab triggers and drive tab changes programmatically using `bootstrap.Tab.getOrCreateInstance(el).show()`, which keeps the Bootstrap JavaScript managing panel visibility while your code controls when a user is allowed to advance.
How does Canvas Builder generate a multi-step form?
Canvas Builder generates the complete multi-step form HTML, including the progress indicator circles, all step panels, Back and Next buttons, and the goToStep JavaScript function, in a single production-ready file. You describe the steps and fields you need (for example, 'a three-step SaaS signup with name, billing, and plan selection') and Canvas Builder maps your brand colours to the Bootstrap utility classes used on the active step circle, the primary action buttons, and the confirmation alert, so the component matches your design system without any manual CSS editing.