Snippets Form Wizard

Bootstrap 5 Multi-Step Request a Quote Form

A multi-step quote request form with a progress bar, selectable service cards, personal and company detail steps with validation, and a success screen. Built with Bootstrap 5 form components and a short vanilla script.

Bootstrap 5 No jQuery Jun 2020 3.7K views

<section class="wdw-stage">
  <div class="container" style="max-width:640px">
    <form class="wdw-card p-4 p-md-5 q-wizard" novalidate aria-labelledby="q-title">
      <h1 id="q-title" class="wdw-heading h3 mb-1">Request a quote</h1>
      <p class="wdw-muted mb-4">Fill out the form or call <a href="tel:+11234567891" class="fw-semibold link-primary link-underline-opacity-0">123 456 7891</a> to start protecting your business today.</p>

      <div class="d-flex align-items-center gap-3 mb-4">
        <div class="progress flex-grow-1" role="progressbar" aria-label="Quote progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="25" style="height:.5rem">
          <div class="progress-bar rounded-pill" id="q-bar" style="width:25%"></div>
        </div>
        <span class="small fw-semibold wdw-muted text-nowrap" id="q-count">Step 1 of 3</span>
      </div>

      <div class="q-panel" data-panel="0">
        <h2 class="h6 fw-bold mb-3">Select service(s)</h2>
        <div class="row g-3">
          <div class="col-6">
            <input type="checkbox" class="btn-check" id="svc-paper" name="service" value="paper" autocomplete="off">
            <label class="svc-card" for="svc-paper">
              <span class="wdw-icon mb-2"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8Z"/><path d="M14 3v5h5M9 13h6M9 17h6"/></svg></span>
              <span class="fw-semibold">One-time paper cleanout</span>
              <span class="small wdw-muted">Clear out stored records</span>
            </label>
          </div>
          <div class="col-6">
            <input type="checkbox" class="btn-check" id="svc-regular" name="service" value="regular" autocomplete="off">
            <label class="svc-card" for="svc-regular">
              <span class="wdw-icon mb-2"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg></span>
              <span class="fw-semibold">Scheduled shredding</span>
              <span class="small wdw-muted">Recurring pickups</span>
            </label>
          </div>
          <div class="col-6">
            <input type="checkbox" class="btn-check" id="svc-drive" name="service" value="drive" autocomplete="off">
            <label class="svc-card" for="svc-drive">
              <span class="wdw-icon mb-2"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.7 3.6 3 8 3s8-1.3 8-3V5M4 11v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/></svg></span>
              <span class="fw-semibold">Hard drive destruction</span>
              <span class="small wdw-muted">Certified media destruction</span>
            </label>
          </div>
          <div class="col-6">
            <input type="checkbox" class="btn-check" id="svc-other" name="service" value="other" autocomplete="off">
            <label class="svc-card" for="svc-other">
              <span class="wdw-icon mb-2"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5Z"/><path d="m3 8 9 5 9-5M12 13v8"/></svg></span>
              <span class="fw-semibold">Other materials</span>
              <span class="small wdw-muted">Uniforms, products, more</span>
            </label>
          </div>
        </div>
        <div class="text-danger small mt-2 d-none" data-err="service">Choose at least one service.</div>
      </div>

      <div class="q-panel d-none" data-panel="1">
        <h2 class="h6 fw-bold mb-3">Personal details</h2>
        <div class="row g-3">
          <div class="col-sm-6"><div class="form-floating"><input class="form-control" id="q-first" placeholder="First name" autocomplete="given-name" required><label for="q-first">First name</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-sm-6"><div class="form-floating"><input class="form-control" id="q-last" placeholder="Last name" autocomplete="family-name" required><label for="q-last">Last name</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-12"><div class="form-floating"><input type="email" class="form-control" id="q-email" placeholder="Email" autocomplete="email" required><label for="q-email">Email</label><div class="invalid-feedback">Enter a valid email.</div></div></div>
          <div class="col-12"><div class="form-floating"><input type="tel" class="form-control" id="q-phone" placeholder="Phone" autocomplete="tel" required><label for="q-phone">Contact number</label><div class="invalid-feedback">Required.</div></div></div>
        </div>
      </div>

      <div class="q-panel d-none" data-panel="2">
        <h2 class="h6 fw-bold mb-3">Company details</h2>
        <div class="row g-3">
          <div class="col-12"><div class="form-floating"><input class="form-control" id="q-company" placeholder="Company" autocomplete="organization" required><label for="q-company">Company name</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-sm-4"><div class="form-floating"><input class="form-control" id="q-zip" placeholder="Zip" autocomplete="postal-code" required><label for="q-zip">Zip code</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-sm-4"><div class="form-floating"><input class="form-control" id="q-state" placeholder="State" required><label for="q-state">State</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-sm-4"><div class="form-floating"><input class="form-control" id="q-city" placeholder="City" autocomplete="address-level2" required><label for="q-city">City</label><div class="invalid-feedback">Required.</div></div></div>
          <div class="col-12"><div class="form-floating"><select class="form-select" id="q-size" required><option value="" selected disabled>Choose…</option><option>1-20 boxes</option><option>20-50 boxes</option><option>50-100 boxes</option><option>100+ boxes</option></select><label for="q-size">Shredding job size</label><div class="invalid-feedback">Choose a size.</div></div></div>
        </div>
      </div>

      <div class="q-panel d-none text-center py-4" data-panel="3" tabindex="-1">
        <span class="q-check mb-3" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></span>
        <h2 class="h4 fw-bold">Success!</h2>
        <p class="wdw-muted mb-0">Thank you for choosing us. A specialist will send your quote within one business day.</p>
      </div>

      <div class="d-flex justify-content-between gap-2 mt-4" id="q-actions">
        <button type="button" class="btn btn-outline-primary rounded-pill px-4 invisible" data-prev>Back</button>
        <button type="button" class="btn btn-primary rounded-pill px-4" data-next>Continue</button>
      </div>
    </form>
  </div>
</section>

Built on Bootstrap 5.3.8 with plain JavaScript — no jQuery. Supports light and dark mode via data-bs-theme.