Open demo

CSS code

HTML
<div><span class="lbl">Progress for a multi-page checkout</span>
<div class="ck-prog">
  <div class="ck-card ck-top">
    <div class="ck-brand"><b>Saltnorth Supply</b><span class="ck-secure"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Secure checkout</span></div>
    <nav class="ck-chevs" aria-label="Checkout progress">
      <ol>
        <li data-state="done"><a href="#"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg><span class="ck-name">Cart</span><span class="sr-only">, completed</span></a></li>
        <li data-state="current" aria-current="step"><span class="ck-in"><span class="ck-n">2</span><span class="ck-name">Shipping</span></span></li>
        <li data-state="next"><span class="ck-in"><span class="ck-n">3</span><span class="ck-name">Payment</span></span></li>
        <li data-state="next"><span class="ck-in"><span class="ck-n">4</span><span class="ck-name">Review</span></span></li>
      </ol>
    </nav>
  </div>
  <div class="ck-card ck-slim">
    <nav class="ck-line" aria-label="Checkout progress">
      <ol>
        <li data-state="done"><a href="#"><span class="ck-c"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Cart<span class="sr-only">, completed</span></a><span class="ck-sep" aria-hidden="true">/</span></li>
        <li data-state="done"><a href="#"><span class="ck-c"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="sr-only">, completed</span></a><span class="ck-sep" aria-hidden="true">/</span></li>
        <li data-state="current" aria-current="step"><span class="ck-c">3</span>Payment<span class="ck-sep" aria-hidden="true">/</span></li>
        <li data-state="next"><span class="ck-c">4</span>Review</li>
      </ol>
    </nav>
  </div>
</div></div>

<div><span class="lbl">Single-page checkout</span>
<form class="ck" data-wizard data-subtotal="121" aria-labelledby="co-title">
  <div class="ck-card ck-main">
    <div class="ck-head"><h2 class="ck-title" id="co-title">Checkout</h2><span class="ck-secure"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Saltnorth Supply · Secure checkout</span></div>
    <ol class="ck-steps" data-stepper aria-label="Progress">
      <li><span class="ck-num"><b>01</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="sr-only" data-sr></span></li>
      <li><span class="ck-num"><b>02</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Payment<span class="sr-only" data-sr></span></li>
      <li><span class="ck-num"><b>03</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Review<span class="sr-only" data-sr></span></li>
    </ol>

    <section class="ck-panel" data-step aria-labelledby="co-h1">
      <h3 class="ck-h" id="co-h1" tabindex="-1"><span class="ck-kick">Step 1 of 3</span>Where should we send it?</h3>
      <div class="ck-field"><label for="co-name">Full name</label>
        <input class="ck-input" id="co-name" name="name" required autocomplete="name" value="Maya Okafor"></div>
      <div class="ck-field"><label for="co-street">Street address</label>
        <input class="ck-input" id="co-street" name="street" required autocomplete="street-address" value="418 Alder Street, Apt 3"></div>
      <div class="ck-row">
        <div class="ck-field"><label for="co-city">City</label><input class="ck-input" id="co-city" name="city" required autocomplete="address-level2" value="Portland"></div>
        <div class="ck-field"><label for="co-zip">Postcode</label><input class="ck-input" id="co-zip" name="postcode" required autocomplete="postal-code" value="97205"></div>
        <div class="ck-field"><label for="co-country">Country</label>
          <select class="ck-input" id="co-country" name="country" autocomplete="country-name"><option>United States</option><option>Canada</option><option>United Kingdom</option><option>Ireland</option><option>Australia</option></select></div>
      </div>
      <fieldset class="ck-field"><legend class="ck-legend">Delivery</legend>
        <div class="ck-tiles">
          <label class="ck-tile"><input type="radio" name="delivery" value="Standard, 3–5 business days" data-cost="0" required><span><b>Standard</b><span>3–5 business days</span></span><em>Free</em></label>
          <label class="ck-tile"><input type="radio" name="delivery" value="Express, next business day" data-cost="12" checked><span><b>Express</b><span>Next business day</span></span><em>$12.00</em></label>
        </div></fieldset>
    </section>

    <section class="ck-panel" data-step aria-labelledby="co-h2">
      <h3 class="ck-h" id="co-h2" tabindex="-1"><span class="ck-kick">Step 2 of 3</span>How would you like to pay?</h3>
      <div class="ck-field"><label for="co-card">Card number</label>
        <input class="ck-input" id="co-card" name="card" required inputmode="numeric" autocomplete="cc-number" pattern="(?:[0-9] ?){12,18}[0-9]" maxlength="23" aria-describedby="co-card-hint" placeholder="1234 5678 9012 3456" value="4242 4242 4242 4242">
        <span class="ck-hint" id="co-card-hint">13 to 19 digits, spaces are fine.</span></div>
      <div class="ck-row">
        <div class="ck-field"><label for="co-exp">Expiry date</label>
          <input class="ck-input" id="co-exp" name="expiry" required inputmode="numeric" autocomplete="cc-exp" pattern="(0[1-9]|1[0-2]) ?/ ?[0-9]{2}" maxlength="7" aria-describedby="co-exp-hint" placeholder="MM/YY" value="08/29">
          <span class="ck-hint" id="co-exp-hint">MM/YY</span></div>
        <div class="ck-field"><label for="co-cvc">Security code</label>
          <input class="ck-input" id="co-cvc" name="cvc" required inputmode="numeric" autocomplete="cc-csc" pattern="[0-9]{3,4}" maxlength="4" aria-describedby="co-cvc-hint" value="314">
          <span class="ck-hint" id="co-cvc-hint">3 or 4 digits on the back of the card.</span></div>
      </div>
      <div class="ck-field"><label for="co-holder">Name on card</label>
        <input class="ck-input" id="co-holder" name="holder" required autocomplete="cc-name" value="Maya Okafor"></div>
      <label class="ck-check"><input type="checkbox" name="billing" value="same" checked>Billing address same as shipping</label>
    </section>

    <section class="ck-panel" data-step aria-labelledby="co-h3">
      <h3 class="ck-h" id="co-h3" tabindex="-1"><span class="ck-kick">Step 3 of 3</span>Check and pay</h3>
      <dl class="ck-review">
        <div><dt>Name</dt><dd data-out="name">Maya Okafor</dd></div>
        <div><dt>Ship to</dt><dd><span data-out="street">418 Alder Street, Apt 3</span>, <span data-out="city">Portland</span> <span data-out="postcode">97205</span>, <span data-out="country">United States</span></dd></div>
        <div><dt>Delivery</dt><dd data-out="delivery">Express, next business day</dd></div>
        <div><dt>Payment</dt><dd>Card ending <span data-out-last4="card">4242</span></dd></div>
      </dl>
    </section>

    <section class="ck-panel ck-done" data-done hidden aria-labelledby="co-h4">
      <span><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
      <h3 class="ck-h" id="co-h4" tabindex="-1">Order SN-40718 confirmed</h3>
      <p>Thank you, Maya. Your parcel is being packed and tracking details follow as soon as it ships.</p>
      <button type="button" class="ck-btn ghost" data-restart>Start a new order</button>
    </section>

    <div class="ck-nav">
      <button type="button" class="ck-btn ghost" data-back hidden>Back</button>
      <button type="button" class="ck-btn" data-next hidden>Continue</button>
      <button type="submit" class="ck-btn"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg><span>Pay <span data-total>$133.00</span></span></button>
    </div>
  </div>

  <aside class="ck-card ck-sum" aria-labelledby="co-sum">
    <h3 id="co-sum">Order summary</h3>
    <ul class="ck-items">
      <li><span class="ck-thumb sand" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M8.5 3.5 4 6 2.5 10l3 1.2L7 9.8V20.5h10V9.8l1.5 1.4 3-1.2L20 6l-4.5-2.5c-.7 1.3-2 2-3.5 2s-2.8-.7-3.5-2Z"/></svg></span><span class="ck-item"><b>Linen Overshirt</b><small>Sand, M · Qty 1</small></span><span class="ck-price">$89.00</span></li>
      <li><span class="ck-thumb coal" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M5 14a7 7 0 0 1 14 0M4 14h16v5.5H4zM8.5 14v5.5M12 14v5.5M15.5 14v5.5"/><circle cx="12" cy="5" r="1.8"/></svg></span><span class="ck-item"><b>Merino Beanie</b><small>Charcoal · Qty 1</small></span><span class="ck-price">$32.00</span></li>
    </ul>
    <dl class="ck-totals">
      <div><dt>Subtotal</dt><dd>$121.00</dd></div>
      <div><dt>Shipping</dt><dd data-ship>$12.00</dd></div>
      <div class="ck-grand" aria-live="polite" aria-atomic="true"><dt>Total</dt><dd data-total>$133.00</dd></div>
    </dl>
  </aside>
</form></div>
CSS
/* Checkout wizards. A: a static progress trail for a checkout split over several pages (no script) in two
   styles, chevrons and a slim numbered line. B: a single-page checkout wizard with an order summary beside it.
   Its script shows one step at a time, sets data-state and aria-current="step" on the stepper, moves focus to the
   new step's heading, keeps shipping and totals in line with the delivery choice and shows only the card's last
   four digits in the review. Without JavaScript every step shows and the Pay button submits the form normally. */
.ck,.ck-prog{--ck-accent:#c2410c;--ck-dark:#9a3412;--ck-soft:#ffedd5;--ck-tint:#fff7ed;--ck-ink:#1c1917;--ck-muted:#57534e;
  --ck-field:#8f867e;--ck-track:#e2dcd4;--ck-rule:#e7e2da;--ck-stone:#efebe5;color:var(--ck-ink)}
.ck [hidden]{display:none!important}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.ck-card{background:#fff;border:1px solid var(--ck-rule);border-radius:16px;box-shadow:0 1px 2px rgba(28,25,23,.05),0 12px 28px -18px rgba(124,45,18,.22)}
.ck-secure{display:inline-flex;align-items:center;gap:6px;font-size:.82rem;color:var(--ck-muted)}
.ck-secure svg,.ck-btn svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ck-tick{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;flex:none}

/* A1 chevrons: the arrow shape is a clip-path on ::before, so focus outlines on the links are never clipped */
.ck-prog{display:grid;gap:16px}
.ck-top{padding:22px 26px 26px}
.ck-brand{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:18px}
.ck-brand b{display:inline-flex;align-items:center;gap:9px;font-size:1.05rem;letter-spacing:-.01em}
.ck-brand b::before{content:"";width:22px;height:22px;border-radius:7px;background:var(--ck-accent);box-shadow:inset -6px -6px 0 var(--ck-dark)}
.ck-chevs ol{list-style:none;margin:0;padding:0;display:flex}
.ck-chevs li{position:relative;isolation:isolate;flex:1;min-width:0;display:flex;height:50px;padding:0 14px;font-size:.92rem;color:var(--ck-muted)}
.ck-chevs li + li{margin-left:-10px}
.ck-chevs li::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--ck-stone);transition:background .2s;
  clip-path:polygon(0 0,calc(100% - 14px) 0,100% 50%,calc(100% - 14px) 100%,0 100%,14px 50%)}
.ck-chevs li:first-child{padding-left:0}
.ck-chevs li:first-child::before{border-radius:10px 0 0 10px;clip-path:polygon(0 0,calc(100% - 14px) 0,100% 50%,calc(100% - 14px) 100%,0 100%)}
.ck-chevs li:last-child{padding-right:0}
.ck-chevs li:last-child::before{border-radius:0 10px 10px 0;clip-path:polygon(0 0,100% 0,100% 100%,0 100%,14px 50%)}
.ck-chevs a,.ck-chevs .ck-in{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:8px;color:inherit;text-decoration:none;border-radius:6px;white-space:nowrap}
.ck-chevs a:hover .ck-name{text-decoration:underline;text-underline-offset:3px}
.ck-chevs a:focus-visible{outline:2px solid var(--ck-ink);outline-offset:-4px}
.ck-chevs [data-state="done"]{color:var(--ck-dark);font-weight:600}
.ck-chevs [data-state="done"]::before{background:var(--ck-soft)}
.ck-chevs [data-state="done"]:hover::before{background:#fed7aa}
.ck-chevs [data-state="current"]{color:#fff;font-weight:600}
.ck-chevs [data-state="current"]::before{background:var(--ck-accent)}
.ck-n{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;border:1.5px solid currentColor;font-size:.76rem;font-weight:700;flex:none}
@media (max-width:560px){.ck-top{padding:18px 16px 20px}
  .ck-chevs li{flex:none;width:60px;height:46px}.ck-chevs li:first-child{width:50px}.ck-chevs [data-state="current"]{flex:1;width:auto}
  .ck-chevs li:not([data-state="current"]) .ck-name{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}}

/* A2 slim line: small numbered circles, done steps are links, separators are hidden from screen readers */
.ck-slim{padding:14px 22px}
.ck-line ol{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;font-size:.9rem;color:var(--ck-muted)}
.ck-line li{display:flex;align-items:center;gap:8px}
.ck-sep{color:#78716c;margin-left:4px;font-weight:400}
.ck-line a{display:inline-flex;align-items:center;gap:8px;color:var(--ck-dark);font-weight:600;text-decoration:underline;text-decoration-color:rgba(154,52,18,.35);text-underline-offset:4px;border-radius:4px}
.ck-line a:hover{text-decoration-color:currentColor}
.ck-line a:focus-visible{outline:2px solid var(--ck-accent);outline-offset:3px}
.ck-c{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;border:1.5px solid currentColor;font-size:.72rem;font-weight:700;flex:none}
.ck-c .ck-tick{width:13px;height:13px}
.ck-line [data-state="done"] .ck-c{background:var(--ck-soft);border-color:var(--ck-soft)}
.ck-line [data-state="current"]{color:var(--ck-ink);font-weight:600}
.ck-line [data-state="current"] .ck-c{background:var(--ck-accent);border-color:var(--ck-accent);color:#fff}
@media (max-width:560px){.ck-slim{padding:12px 16px}.ck-line ol{gap:6px 8px;font-size:.84rem}.ck-line li{gap:6px}.ck-sep{margin-left:2px}.ck-c{width:20px;height:20px}}

/* B layout: form card and order summary side by side, stacked below 992px */
.ck{display:grid;gap:24px;align-items:start}
@media (min-width:992px){.ck{grid-template-columns:2fr 1fr}.ck-sum{position:sticky;top:20px}}
.ck-main{padding:28px 32px;min-width:0}
.ck-head{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.ck-title{font-size:1.35rem;font-weight:700;letter-spacing:-.015em;margin:0}

/* stepper: zero-padded numbers over a thin track that fills to half on the current step and fully when done */
.ck-steps{list-style:none;margin:22px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.ck-steps li{position:relative;display:flex;align-items:center;gap:10px;padding-bottom:12px;font-size:.9rem;color:var(--ck-muted);min-width:0}
.ck-steps li::after,.ck-steps li::before{content:"";position:absolute;left:0;bottom:0;height:3px;border-radius:3px}
.ck-steps li::after{right:0;background:var(--ck-track)}
.ck-steps li::before{width:0;z-index:1;background:var(--ck-accent);transition:width .35s ease}
.ck-num{display:grid;place-items:center;min-width:28px;height:26px;padding:0 4px;border-radius:7px;background:var(--ck-stone);font-size:.78rem;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.03em;transition:background .25s,color .25s}
.ck-num svg{display:none;width:15px;height:15px}
.ck-steps [data-state="current"]{color:var(--ck-ink);font-weight:600}
.ck-steps [data-state="current"]::before{width:50%}
.ck-steps [data-state="current"] .ck-num{background:var(--ck-accent);color:#fff}
.ck-steps [data-state="done"]{color:var(--ck-ink)}
.ck-steps [data-state="done"]::before{width:100%}
.ck-steps [data-state="done"] .ck-num{background:var(--ck-soft);color:var(--ck-dark)}
.ck-steps [data-state="done"] .ck-num b{display:none}
.ck-steps [data-state="done"] .ck-num svg{display:block}

/* step panels and fields */
.ck-panel{margin-top:26px;display:grid;gap:16px;animation:ck-in .3s ease}
@keyframes ck-in{from{opacity:0;transform:translateY(6px)}}
.ck-h{margin:0;font-size:1.12rem;font-weight:700;letter-spacing:-.01em}
.ck-h:focus{outline:none}
.ck-kick{display:block;font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ck-dark);margin-bottom:2px}
.ck-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
.ck-field{display:grid;gap:6px;min-width:0;align-content:start}
.ck-field > label,.ck-legend{font-size:.88rem;font-weight:600}
.ck-hint{font-size:.8rem;color:var(--ck-muted)}
.ck-input{width:100%;font:inherit;font-size:.95rem;color:var(--ck-ink);background:#fff;border:1.5px solid var(--ck-field);border-radius:10px;padding:10px 12px;min-height:44px}
.ck-input::placeholder{color:#6f6862}
.ck-input:focus-visible{outline:none;border-color:var(--ck-accent);box-shadow:0 0 0 4px var(--ck-soft)}
fieldset.ck-field{border:0;margin:0;padding:0}
.ck-legend{padding:0;margin-bottom:6px}
.ck-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.ck-tile{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border:1.5px solid var(--ck-field);border-radius:12px;cursor:pointer;transition:border-color .2s,background .2s}
.ck-tile input,.ck-check input{width:18px;height:18px;margin:2px 0 0;accent-color:var(--ck-accent);flex:none}
.ck-tile input:focus-visible,.ck-check input:focus-visible{outline:2px solid var(--ck-accent);outline-offset:3px}
.ck-tile > span{flex:1;display:grid;gap:2px}
.ck-tile b{font-size:.95rem}
.ck-tile span span{font-size:.82rem;color:var(--ck-muted)}
.ck-tile em{font-style:normal;font-weight:700;font-size:.92rem}
.ck-tile:has(:checked){border-color:var(--ck-accent);background:var(--ck-tint)}
.ck-check{display:flex;align-items:flex-start;gap:10px;font-size:.92rem;cursor:pointer}

/* review list */
.ck-review{margin:0;display:grid;border:1px solid var(--ck-rule);border-radius:12px;overflow:hidden}
.ck-review div{display:flex;justify-content:space-between;gap:16px;padding:11px 14px;font-size:.92rem}
.ck-review div + div{border-top:1px solid var(--ck-rule)}
.ck-review dt{color:var(--ck-muted);flex:none}
.ck-review dd{margin:0;font-weight:600;text-align:right;overflow-wrap:anywhere}

/* Back / Continue / Pay bar and done panel */
.ck-nav{display:flex;gap:10px;margin-top:26px;padding-top:20px;border-top:1px solid var(--ck-rule)}
.ck-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;padding:0 22px;border-radius:10px;border:1.5px solid var(--ck-accent);background:var(--ck-accent);color:#fff;font:inherit;font-size:.95rem;font-weight:600;cursor:pointer;transition:background .2s,box-shadow .2s}
.ck-btn:hover{background:var(--ck-dark);border-color:var(--ck-dark)}
.ck-btn:focus-visible{outline:none;box-shadow:0 0 0 3px #fff,0 0 0 5px var(--ck-accent)}
.ck-btn.ghost{background:#fff;color:var(--ck-ink);border-color:var(--ck-field)}
.ck-btn.ghost:hover{background:var(--ck-tint)}
.ck-nav .ck-btn:not(.ghost){margin-left:auto}
.ck-done{text-align:center;justify-items:center;padding:12px 0 4px}
.ck-done > span{display:grid;place-items:center;width:56px;height:56px;border-radius:50%;background:var(--ck-soft);color:var(--ck-dark)}
.ck-done .ck-tick{width:26px;height:26px}
.ck-done p{margin:0;color:var(--ck-muted);font-size:.92rem;max-width:40ch}

/* order summary */
.ck-sum{padding:24px}
.ck-sum h3{margin:0 0 14px;font-size:1rem;font-weight:700}
.ck-items{list-style:none;margin:0;padding:0 0 16px;display:grid;gap:14px;border-bottom:1px solid var(--ck-rule)}
.ck-items li{display:flex;align-items:center;gap:12px;font-size:.9rem}
.ck-thumb{flex:none;display:grid;place-items:center;width:52px;height:52px;border-radius:12px;color:rgba(255,255,255,.9)}
.ck-thumb svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round}
.ck-thumb.sand{background:linear-gradient(135deg,#e6d6b8,#c2a878)}
.ck-thumb.coal{background:linear-gradient(135deg,#6b6561,#35312f)}
.ck-item{display:grid;flex:1;min-width:0}
.ck-items small{font-size:.82rem;color:var(--ck-muted)}
.ck-items b{font-weight:600}
.ck-price{font-weight:600;font-variant-numeric:tabular-nums}
.ck-totals{margin:0;padding-top:14px;display:grid;gap:8px;font-size:.92rem}
.ck-totals div{display:flex;justify-content:space-between;gap:12px}
.ck-totals dt{color:var(--ck-muted)}
.ck-totals dd{margin:0;font-variant-numeric:tabular-nums}
.ck-totals .ck-grand{margin-top:6px;padding-top:12px;border-top:1px solid var(--ck-rule);font-size:1.05rem;font-weight:700}
.ck-totals .ck-grand dt{color:var(--ck-ink)}
@media (prefers-reduced-motion:reduce){.ck *,.ck *::before,.ck-prog *::before{transition:none!important;animation:none!important}}
@media (max-width:600px){.ck-main{padding:24px 18px}.ck-sum{padding:20px 18px}.ck-steps{gap:8px}.ck-steps li{gap:7px;font-size:.8rem}.ck-num{min-width:24px;height:24px}}
JavaScript
// Form wizard: shows one step at a time, marks the stepper with data-state and aria-current="step",
// checks the step's fields before moving on and moves focus to the new step's heading.
// Checkout: the delivery choice ([data-cost]) updates [data-ship] and every [data-total]; [data-out-last4] shows only a card's last four digits.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
  }
  function price() {
    if (!wz.dataset.subtotal) return;
    var d = wz.querySelector('[data-cost]:checked'), c = d ? +d.dataset.cost : 0;
    wz.querySelectorAll('[data-ship]').forEach(function (o) { o.textContent = c ? '$' + c.toFixed(2) : 'Free'; });
    wz.querySelectorAll('[data-total]').forEach(function (o) { o.textContent = '$' + (+wz.dataset.subtotal + c).toFixed(2); });
  }
  function go(i, focus) {
    at = i; mark(i); price();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    wz.querySelectorAll('[data-out-last4]').forEach(function (o) {
      var f = wz.elements[o.dataset.outLast4]; o.textContent = f ? f.value.replace(/\D/g, '').slice(-4) : '';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  wz.noValidate = true;
  wz.addEventListener('change', price);
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Progress for a multi-page checkout</span>
<div class="ck-prog">
  <div class="card ck-card ck-top">
    <div class="ck-brand"><b>Saltnorth Supply</b><span class="ck-secure"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Secure checkout</span></div>
    <nav class="ck-chevs" aria-label="Checkout progress">
      <ol>
        <li data-state="done"><a href="#"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg><span class="ck-name">Cart</span><span class="visually-hidden">, completed</span></a></li>
        <li data-state="current" aria-current="step"><span class="ck-in"><span class="ck-n">2</span><span class="ck-name">Shipping</span></span></li>
        <li data-state="next"><span class="ck-in"><span class="ck-n">3</span><span class="ck-name">Payment</span></span></li>
        <li data-state="next"><span class="ck-in"><span class="ck-n">4</span><span class="ck-name">Review</span></span></li>
      </ol>
    </nav>
  </div>
  <div class="card ck-card ck-slim">
    <nav aria-label="Checkout progress">
      <ol class="breadcrumb ck-line">
        <li class="breadcrumb-item" data-state="done"><a href="#"><span class="ck-c"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Cart<span class="visually-hidden">, completed</span></a><span class="ck-sep" aria-hidden="true">/</span></li>
        <li class="breadcrumb-item" data-state="done"><a href="#"><span class="ck-c"><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="visually-hidden">, completed</span></a><span class="ck-sep" aria-hidden="true">/</span></li>
        <li class="breadcrumb-item active" data-state="current" aria-current="step"><span class="ck-c">3</span>Payment<span class="ck-sep" aria-hidden="true">/</span></li>
        <li class="breadcrumb-item" data-state="next"><span class="ck-c">4</span>Review</li>
      </ol>
    </nav>
  </div>
</div></div>

<div><span class="lbl">Single-page checkout</span>
<form class="ck row g-4 align-items-start" data-wizard data-subtotal="121" aria-labelledby="co-title">
  <div class="col-lg-8"><div class="card ck-card ck-main">
    <div class="ck-head"><h2 class="ck-title fw-bold mb-0" id="co-title">Checkout</h2><span class="ck-secure"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Saltnorth Supply · Secure checkout</span></div>
    <ol class="ck-steps" data-stepper aria-label="Progress">
      <li><span class="ck-num"><b>01</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="visually-hidden" data-sr></span></li>
      <li><span class="ck-num"><b>02</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Payment<span class="visually-hidden" data-sr></span></li>
      <li><span class="ck-num"><b>03</b><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Review<span class="visually-hidden" data-sr></span></li>
    </ol>

    <section class="ck-panel" data-step aria-labelledby="co-h1">
      <h3 class="ck-h fw-bold mb-0" id="co-h1" tabindex="-1"><span class="ck-kick">Step 1 of 3</span>Where should we send it?</h3>
      <div><label class="form-label" for="co-name">Full name</label>
        <input class="form-control" id="co-name" name="name" required autocomplete="name" value="Maya Okafor"></div>
      <div><label class="form-label" for="co-street">Street address</label>
        <input class="form-control" id="co-street" name="street" required autocomplete="street-address" value="418 Alder Street, Apt 3"></div>
      <div class="row g-3">
        <div class="col-sm-4"><label class="form-label" for="co-city">City</label><input class="form-control" id="co-city" name="city" required autocomplete="address-level2" value="Portland"></div>
        <div class="col-sm-4"><label class="form-label" for="co-zip">Postcode</label><input class="form-control" id="co-zip" name="postcode" required autocomplete="postal-code" value="97205"></div>
        <div class="col-sm-4"><label class="form-label" for="co-country">Country</label>
          <select class="form-select" id="co-country" name="country" autocomplete="country-name"><option>United States</option><option>Canada</option><option>United Kingdom</option><option>Ireland</option><option>Australia</option></select></div>
      </div>
      <fieldset><legend>Delivery</legend>
        <div class="ck-tiles">
          <label class="ck-tile"><input class="form-check-input" type="radio" name="delivery" value="Standard, 3–5 business days" data-cost="0" required><span><b>Standard</b><span>3–5 business days</span></span><em>Free</em></label>
          <label class="ck-tile"><input class="form-check-input" type="radio" name="delivery" value="Express, next business day" data-cost="12" checked><span><b>Express</b><span>Next business day</span></span><em>$12.00</em></label>
        </div></fieldset>
    </section>

    <section class="ck-panel" data-step aria-labelledby="co-h2">
      <h3 class="ck-h fw-bold mb-0" id="co-h2" tabindex="-1"><span class="ck-kick">Step 2 of 3</span>How would you like to pay?</h3>
      <div><label class="form-label" for="co-card">Card number</label>
        <input class="form-control" id="co-card" name="card" required inputmode="numeric" autocomplete="cc-number" pattern="(?:[0-9] ?){12,18}[0-9]" maxlength="23" aria-describedby="co-card-hint" placeholder="1234 5678 9012 3456" value="4242 4242 4242 4242">
        <div class="form-text" id="co-card-hint">13 to 19 digits, spaces are fine.</div></div>
      <div class="row g-3">
        <div class="col-sm-6"><label class="form-label" for="co-exp">Expiry date</label>
          <input class="form-control" id="co-exp" name="expiry" required inputmode="numeric" autocomplete="cc-exp" pattern="(0[1-9]|1[0-2]) ?/ ?[0-9]{2}" maxlength="7" aria-describedby="co-exp-hint" placeholder="MM/YY" value="08/29">
          <div class="form-text" id="co-exp-hint">MM/YY</div></div>
        <div class="col-sm-6"><label class="form-label" for="co-cvc">Security code</label>
          <input class="form-control" id="co-cvc" name="cvc" required inputmode="numeric" autocomplete="cc-csc" pattern="[0-9]{3,4}" maxlength="4" aria-describedby="co-cvc-hint" value="314">
          <div class="form-text" id="co-cvc-hint">3 or 4 digits on the back of the card.</div></div>
      </div>
      <div><label class="form-label" for="co-holder">Name on card</label>
        <input class="form-control" id="co-holder" name="holder" required autocomplete="cc-name" value="Maya Okafor"></div>
      <div class="form-check"><input class="form-check-input" type="checkbox" id="co-billing" name="billing" value="same" checked><label class="form-check-label" for="co-billing">Billing address same as shipping</label></div>
    </section>

    <section class="ck-panel" data-step aria-labelledby="co-h3">
      <h3 class="ck-h fw-bold mb-0" id="co-h3" tabindex="-1"><span class="ck-kick">Step 3 of 3</span>Check and pay</h3>
      <dl class="list-group mb-0">
        <div class="list-group-item d-flex justify-content-between gap-3"><dt>Name</dt><dd data-out="name">Maya Okafor</dd></div>
        <div class="list-group-item d-flex justify-content-between gap-3"><dt>Ship to</dt><dd><span data-out="street">418 Alder Street, Apt 3</span>, <span data-out="city">Portland</span> <span data-out="postcode">97205</span>, <span data-out="country">United States</span></dd></div>
        <div class="list-group-item d-flex justify-content-between gap-3"><dt>Delivery</dt><dd data-out="delivery">Express, next business day</dd></div>
        <div class="list-group-item d-flex justify-content-between gap-3"><dt>Payment</dt><dd>Card ending <span data-out-last4="card">4242</span></dd></div>
      </dl>
    </section>

    <section class="ck-panel ck-done" data-done hidden aria-labelledby="co-h4">
      <span><svg class="ck-tick" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
      <h3 class="ck-h fw-bold mb-0" id="co-h4" tabindex="-1">Order SN-40718 confirmed</h3>
      <p class="mb-0">Thank you, Maya. Your parcel is being packed and tracking details follow as soon as it ships.</p>
      <button type="button" class="btn btn-outline-secondary" data-restart>Start a new order</button>
    </section>

    <div class="ck-nav">
      <button type="button" class="btn btn-outline-secondary" data-back hidden>Back</button>
      <button type="button" class="btn btn-primary" data-next hidden>Continue</button>
      <button type="submit" class="btn btn-primary"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg><span>Pay <span data-total>$133.00</span></span></button>
    </div>
  </div></div>

  <div class="col-lg-4"><aside class="card ck-card ck-sum" aria-labelledby="co-sum">
    <h3 class="fs-6 fw-bold mb-3" id="co-sum">Order summary</h3>
    <ul class="ck-items list-unstyled mb-0">
      <li><span class="ck-thumb sand" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M8.5 3.5 4 6 2.5 10l3 1.2L7 9.8V20.5h10V9.8l1.5 1.4 3-1.2L20 6l-4.5-2.5c-.7 1.3-2 2-3.5 2s-2.8-.7-3.5-2Z"/></svg></span><span class="ck-item"><b>Linen Overshirt</b><small>Sand, M · Qty 1</small></span><span class="ck-price">$89.00</span></li>
      <li><span class="ck-thumb coal" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M5 14a7 7 0 0 1 14 0M4 14h16v5.5H4zM8.5 14v5.5M12 14v5.5M15.5 14v5.5"/><circle cx="12" cy="5" r="1.8"/></svg></span><span class="ck-item"><b>Merino Beanie</b><small>Charcoal · Qty 1</small></span><span class="ck-price">$32.00</span></li>
    </ul>
    <dl class="ck-totals mb-0">
      <div class="d-flex justify-content-between gap-3"><dt>Subtotal</dt><dd>$121.00</dd></div>
      <div class="d-flex justify-content-between gap-3"><dt>Shipping</dt><dd data-ship>$12.00</dd></div>
      <div class="ck-grand d-flex justify-content-between gap-3" aria-live="polite" aria-atomic="true"><dt>Total</dt><dd data-total>$133.00</dd></div>
    </dl>
  </aside></div>
</form></div>
CSS
/* Checkout wizards on Bootstrap 5: .card, .breadcrumb, .row/.col, .form-control, .form-select, .form-check,
   .list-group and .btn, restyled through Bootstrap's CSS variables. The chevrons and the stepper are custom.
   A: a static progress trail for a checkout split over several pages (no script). B: a single-page checkout wizard.
   Its script shows one step at a time, sets data-state and aria-current="step" on the stepper, moves focus to the
   new step's heading, keeps shipping and totals in line with the delivery choice and shows only the card's last
   four digits in the review. Without JavaScript every step shows and the Pay button submits the form normally. */
.ck,.ck-prog{--ck-accent:#c2410c;--ck-dark:#9a3412;--ck-soft:#ffedd5;--ck-tint:#fff7ed;--ck-ink:#1c1917;--ck-muted:#57534e;
  --ck-field:#8f867e;--ck-track:#e2dcd4;--ck-rule:#e7e2da;--ck-stone:#efebe5;
  --bs-border-color:#8f867e;--bs-border-radius:10px;--bs-body-color:#1c1917;--bs-secondary-color:#57534e;color:var(--ck-ink)}
.ck-card{--bs-card-border-color:var(--ck-rule);--bs-card-border-radius:16px;--bs-card-inner-border-radius:15px;box-shadow:0 1px 2px rgba(28,25,23,.05),0 12px 28px -18px rgba(124,45,18,.22)}
.ck-secure{display:inline-flex;align-items:center;gap:6px;font-size:.82rem;color:var(--ck-muted)}
.ck-secure svg,.ck .btn svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ck-tick{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;flex:none}

/* A1 chevrons: the arrow shape is a clip-path on ::before, so focus outlines on the links are never clipped */
.ck-prog{display:grid;gap:16px}
.ck-top{padding:22px 26px 26px}
.ck-brand{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:18px}
.ck-brand b{display:inline-flex;align-items:center;gap:9px;font-size:1.05rem;letter-spacing:-.01em}
.ck-brand b::before{content:"";width:22px;height:22px;border-radius:7px;background:var(--ck-accent);box-shadow:inset -6px -6px 0 var(--ck-dark)}
.ck-chevs ol{list-style:none;margin:0;padding:0;display:flex}
.ck-chevs li{position:relative;isolation:isolate;flex:1;min-width:0;display:flex;height:50px;padding:0 14px;font-size:.92rem;color:var(--ck-muted)}
.ck-chevs li + li{margin-left:-10px}
.ck-chevs li::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--ck-stone);transition:background .2s;
  clip-path:polygon(0 0,calc(100% - 14px) 0,100% 50%,calc(100% - 14px) 100%,0 100%,14px 50%)}
.ck-chevs li:first-child{padding-left:0}
.ck-chevs li:first-child::before{border-radius:10px 0 0 10px;clip-path:polygon(0 0,calc(100% - 14px) 0,100% 50%,calc(100% - 14px) 100%,0 100%)}
.ck-chevs li:last-child{padding-right:0}
.ck-chevs li:last-child::before{border-radius:0 10px 10px 0;clip-path:polygon(0 0,100% 0,100% 100%,0 100%,14px 50%)}
.ck-chevs a,.ck-chevs .ck-in{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:8px;color:inherit;text-decoration:none;border-radius:6px;white-space:nowrap}
.ck-chevs a:hover .ck-name{text-decoration:underline;text-underline-offset:3px}
.ck-chevs a:focus-visible{outline:2px solid var(--ck-ink);outline-offset:-4px}
.ck-chevs [data-state="done"]{color:var(--ck-dark);font-weight:600}
.ck-chevs [data-state="done"]::before{background:var(--ck-soft)}
.ck-chevs [data-state="done"]:hover::before{background:#fed7aa}
.ck-chevs [data-state="current"]{color:#fff;font-weight:600}
.ck-chevs [data-state="current"]::before{background:var(--ck-accent)}
.ck-n{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;border:1.5px solid currentColor;font-size:.76rem;font-weight:700;flex:none}

/* A2 slim line: Bootstrap's .breadcrumb with its divider switched off, small numbered circles, done steps are links */
.ck-slim{padding:14px 22px}
.ck-line{--bs-breadcrumb-divider:none;--bs-breadcrumb-margin-bottom:0;--bs-breadcrumb-item-padding-x:0;--bs-breadcrumb-font-size:.9rem;--bs-breadcrumb-item-active-color:var(--ck-ink);align-items:center;gap:8px 12px;color:var(--ck-muted)}
.ck-line .breadcrumb-item{display:flex;align-items:center;gap:8px}
.ck-sep{color:#78716c;margin-left:4px;font-weight:400}
.ck-line a{display:inline-flex;align-items:center;gap:8px;color:var(--ck-dark);font-weight:600;text-decoration:underline;text-decoration-color:rgba(154,52,18,.35);text-underline-offset:4px;border-radius:4px}
.ck-line a:hover{text-decoration-color:currentColor}
.ck-line a:focus-visible{outline:2px solid var(--ck-accent);outline-offset:3px}
.ck-c{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;border:1.5px solid currentColor;font-size:.72rem;font-weight:700;flex:none}
.ck-c .ck-tick{width:13px;height:13px}
.ck-line [data-state="done"] .ck-c{background:var(--ck-soft);border-color:var(--ck-soft)}
.ck-line [data-state="current"]{font-weight:600}
.ck-line [data-state="current"] .ck-c{background:var(--ck-accent);border-color:var(--ck-accent);color:#fff}
@media (max-width:560px){.ck-top{padding:18px 16px 20px}
  .ck-chevs li{flex:none;width:60px;height:46px}.ck-chevs li:first-child{width:50px}.ck-chevs [data-state="current"]{flex:1;width:auto}
  .ck-chevs li:not([data-state="current"]) .ck-name{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
  .ck-slim{padding:12px 16px}.ck-line{--bs-breadcrumb-font-size:.84rem;gap:6px 8px}.ck-line .breadcrumb-item{gap:6px}.ck-sep{margin-left:2px}.ck-c{width:20px;height:20px}}

/* B: form card and order summary in a .row, stacked below lg (992px) */
.ck-main{padding:28px 32px}
.ck-head{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.ck-title{font-size:1.35rem;letter-spacing:-.015em;line-height:1.5}
@media (min-width:992px){.ck-sum{position:sticky;top:20px}}

/* stepper: zero-padded numbers over a thin track that fills to half on the current step and fully when done */
.ck-steps{list-style:none;margin:22px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.ck-steps li{position:relative;display:flex;align-items:center;gap:10px;padding-bottom:12px;font-size:.9rem;color:var(--ck-muted);min-width:0}
.ck-steps li::after,.ck-steps li::before{content:"";position:absolute;left:0;bottom:0;height:3px;border-radius:3px}
.ck-steps li::after{right:0;background:var(--ck-track)}
.ck-steps li::before{width:0;z-index:1;background:var(--ck-accent);transition:width .35s ease}
.ck-num{display:grid;place-items:center;min-width:28px;height:26px;padding:0 4px;border-radius:7px;background:var(--ck-stone);font-size:.78rem;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.03em;transition:background .25s,color .25s}
.ck-num svg{display:none;width:15px;height:15px}
.ck-steps [data-state="current"]{color:var(--ck-ink);font-weight:600}
.ck-steps [data-state="current"]::before{width:50%}
.ck-steps [data-state="current"] .ck-num{background:var(--ck-accent);color:#fff}
.ck-steps [data-state="done"]{color:var(--ck-ink)}
.ck-steps [data-state="done"]::before{width:100%}
.ck-steps [data-state="done"] .ck-num{background:var(--ck-soft);color:var(--ck-dark)}
.ck-steps [data-state="done"] .ck-num b{display:none}
.ck-steps [data-state="done"] .ck-num svg{display:block}

/* step panels and Bootstrap form controls */
.ck-panel{margin-top:26px;display:grid;gap:16px;animation:ck-in .3s ease}
@keyframes ck-in{from{opacity:0;transform:translateY(6px)}}
.ck-h{font-size:1.12rem;letter-spacing:-.01em;line-height:1.5}
.ck-h:focus{outline:none}
.ck-kick{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ck-dark);margin-bottom:2px}
.ck .form-label,.ck legend{font-size:.88rem;font-weight:600;margin-bottom:6px}
.ck .form-text{font-size:.8rem;color:var(--ck-muted);margin-top:6px}
.ck .form-control,.ck .form-select{border-width:1.5px;min-height:44px;padding:10px 12px;font-size:.95rem}
.ck .form-select{padding-right:36px}
.ck .form-control::placeholder{color:#6f6862}
.ck .form-control:focus,.ck .form-select:focus{border-color:var(--ck-accent);box-shadow:0 0 0 4px var(--ck-soft)}
.ck .form-check-input{width:18px;height:18px;border-width:1.5px;border-color:var(--ck-field);margin-top:2px}
.ck .form-check-input:checked{background-color:var(--ck-accent);border-color:var(--ck-accent)}
.ck .form-check-input:focus{border-color:var(--ck-accent);box-shadow:none}
.ck .form-check-input:focus-visible{outline:2px solid var(--ck-accent);outline-offset:3px}
.ck .form-check{display:flex;align-items:flex-start;gap:10px;padding-left:0;margin:0;font-size:.92rem}
.ck .form-check .form-check-input{float:none;margin-left:0;flex:none}
.ck-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.ck-tile{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border:1.5px solid var(--ck-field);border-radius:12px;cursor:pointer;transition:border-color .2s,background .2s}
.ck-tile .form-check-input{margin:2px 0 0;flex:none}
.ck-tile > span{flex:1;display:grid;gap:2px}
.ck-tile b{font-size:.95rem}
.ck-tile span span{font-size:.82rem;color:var(--ck-muted)}
.ck-tile em{font-style:normal;font-weight:700;font-size:.92rem}
.ck-tile:has(:checked){border-color:var(--ck-accent);background:var(--ck-tint)}
.ck .list-group{--bs-list-group-border-color:var(--ck-rule);--bs-list-group-border-radius:12px;--bs-list-group-item-padding-y:11px;--bs-list-group-item-padding-x:14px;font-size:.92rem}
.ck .list-group dt{font-weight:400;color:var(--ck-muted);flex:none}
.ck .list-group dd{margin:0;font-weight:600;text-align:right;overflow-wrap:anywhere}

/* Back / Continue / Pay bar and done panel */
.ck .btn{--bs-btn-padding-x:22px;--bs-btn-font-weight:600;--bs-btn-font-size:.95rem;--bs-btn-border-width:1.5px;--bs-btn-border-radius:10px;min-height:46px;display:inline-flex;align-items:center;justify-content:center;gap:8px}
.ck .btn-primary{--bs-btn-bg:var(--ck-accent);--bs-btn-border-color:var(--ck-accent);--bs-btn-hover-bg:var(--ck-dark);--bs-btn-hover-border-color:var(--ck-dark);--bs-btn-active-bg:var(--ck-dark);--bs-btn-active-border-color:var(--ck-dark)}
.ck .btn-outline-secondary{--bs-btn-color:var(--ck-ink);--bs-btn-bg:#fff;--bs-btn-border-color:var(--ck-field);--bs-btn-hover-bg:var(--ck-tint);--bs-btn-hover-color:var(--ck-ink);--bs-btn-hover-border-color:var(--ck-field);--bs-btn-active-bg:var(--ck-soft);--bs-btn-active-color:var(--ck-ink);--bs-btn-active-border-color:var(--ck-field)}
.ck .btn:focus-visible{box-shadow:0 0 0 3px #fff,0 0 0 5px var(--ck-accent);outline:0}
.ck-nav{display:flex;gap:10px;margin-top:26px;padding-top:20px;border-top:1px solid var(--ck-rule)}
.ck-nav .btn-primary{margin-left:auto}
.ck-done{text-align:center;justify-items:center;padding:12px 0 4px}
.ck-done > span{display:grid;place-items:center;width:56px;height:56px;border-radius:50%;background:var(--ck-soft);color:var(--ck-dark)}
.ck-done .ck-tick{width:26px;height:26px}
.ck-done p{color:var(--ck-muted);font-size:.92rem;max-width:40ch}

/* order summary */
.ck-sum{padding:24px}
.ck-items{display:grid;gap:14px;padding-bottom:16px;border-bottom:1px solid var(--ck-rule)}
.ck-items li{display:flex;align-items:center;gap:12px;font-size:.9rem}
.ck-thumb{flex:none;display:grid;place-items:center;width:52px;height:52px;border-radius:12px;color:rgba(255,255,255,.9)}
.ck-thumb svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round}
.ck-thumb.sand{background:linear-gradient(135deg,#e6d6b8,#c2a878)}
.ck-thumb.coal{background:linear-gradient(135deg,#6b6561,#35312f)}
.ck-item{display:grid;flex:1;min-width:0}
.ck-items small{font-size:.82rem;color:var(--ck-muted)}
.ck-items b{font-weight:600}
.ck-price{font-weight:600;font-variant-numeric:tabular-nums}
.ck-totals{padding-top:14px;display:grid;gap:8px;font-size:.92rem}
.ck-totals dt{font-weight:400;color:var(--ck-muted)}
.ck-totals dd{margin:0;font-variant-numeric:tabular-nums}
.ck-totals .ck-grand{margin-top:6px;padding-top:12px;border-top:1px solid var(--ck-rule);font-size:1.05rem;font-weight:700}
.ck-totals .ck-grand dt{font-weight:700;color:var(--ck-ink)}
@media (prefers-reduced-motion:reduce){.ck *,.ck *::before,.ck-prog *::before{transition:none!important;animation:none!important}}
@media (max-width:600px){.ck-main{padding:24px 18px}.ck-sum{padding:20px 18px}.ck-steps{gap:8px}.ck-steps li{gap:7px;font-size:.8rem}.ck-num{min-width:24px;height:24px}}
JavaScript
// Form wizard: shows one step at a time, marks the stepper with data-state and aria-current="step",
// checks the step's fields before moving on and moves focus to the new step's heading.
// Checkout: the delivery choice ([data-cost]) updates [data-ship] and every [data-total]; [data-out-last4] shows only a card's last four digits.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
  }
  function price() {
    if (!wz.dataset.subtotal) return;
    var d = wz.querySelector('[data-cost]:checked'), c = d ? +d.dataset.cost : 0;
    wz.querySelectorAll('[data-ship]').forEach(function (o) { o.textContent = c ? '$' + c.toFixed(2) : 'Free'; });
    wz.querySelectorAll('[data-total]').forEach(function (o) { o.textContent = '$' + (+wz.dataset.subtotal + c).toFixed(2); });
  }
  function go(i, focus) {
    at = i; mark(i); price();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    wz.querySelectorAll('[data-out-last4]').forEach(function (o) {
      var f = wz.elements[o.dataset.outLast4]; o.textContent = f ? f.value.replace(/\D/g, '').slice(-4) : '';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  wz.noValidate = true;
  wz.addEventListener('change', price);
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-ck-muted uppercase">Progress for a multi-page checkout</span>
<div class="grid gap-4">
  <div class="rounded-2xl border border-ck-rule bg-white shadow-[0_1px_2px_rgba(28,25,23,.05),0_12px_28px_-18px_rgba(124,45,18,.22)] px-[26px] pt-[22px] pb-[26px] max-[560px]:px-4 max-[560px]:pt-[18px] max-[560px]:pb-5">
    <div class="mb-[18px] flex flex-wrap items-center justify-between gap-3"><b class="inline-flex items-center gap-[9px] text-[1.05rem] tracking-[-.01em] before:size-[22px] before:rounded-[7px] before:bg-ck-accent before:shadow-[inset_-6px_-6px_0_var(--color-ck-dark)]">Saltnorth Supply</b><span class="inline-flex items-center gap-1.5 text-[.82rem] text-ck-muted"><svg class="size-[15px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Secure checkout</span></div>
    <nav aria-label="Checkout progress">
      <ol class="flex">
        <li class="relative isolate flex h-[50px] min-w-0 px-3.5 text-[.92rem] not-first:-ml-2.5 first:pl-0 last:pr-0 before:absolute before:inset-0 before:-z-10 before:transition-colors before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%,14px_50%)] first:before:rounded-l-[10px] first:before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%)] last:before:rounded-r-[10px] last:before:[clip-path:polygon(0_0,100%_0,100%_100%,0_100%,14px_50%)] motion-reduce:before:transition-none max-[560px]:h-[46px] flex-1 max-[560px]:w-[60px] max-[560px]:flex-none max-[560px]:first:w-[50px] font-semibold text-ck-dark before:bg-ck-soft hover:before:bg-[#fed7aa]"><a class="flex min-w-0 flex-1 items-center justify-center gap-2 rounded-md whitespace-nowrap hover:underline hover:underline-offset-3 focus-visible:outline-2 focus-visible:outline-offset-[-4px] focus-visible:outline-ck-ink" href="#"><svg class="size-[18px] flex-none fill-none stroke-current stroke-3" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg><span class="max-[560px]:sr-only">Cart</span><span class="sr-only">, completed</span></a></li>
        <li class="relative isolate flex h-[50px] min-w-0 px-3.5 text-[.92rem] not-first:-ml-2.5 first:pl-0 last:pr-0 before:absolute before:inset-0 before:-z-10 before:transition-colors before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%,14px_50%)] first:before:rounded-l-[10px] first:before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%)] last:before:rounded-r-[10px] last:before:[clip-path:polygon(0_0,100%_0,100%_100%,0_100%,14px_50%)] motion-reduce:before:transition-none max-[560px]:h-[46px] flex-1 font-semibold text-white before:bg-ck-accent" aria-current="step"><span class="flex min-w-0 flex-1 items-center justify-center gap-2 rounded-md whitespace-nowrap"><span class="grid size-6 flex-none place-items-center rounded-full border-[1.5px] border-current text-[.76rem] font-bold">2</span><span>Shipping</span></span></li>
        <li class="relative isolate flex h-[50px] min-w-0 px-3.5 text-[.92rem] not-first:-ml-2.5 first:pl-0 last:pr-0 before:absolute before:inset-0 before:-z-10 before:transition-colors before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%,14px_50%)] first:before:rounded-l-[10px] first:before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%)] last:before:rounded-r-[10px] last:before:[clip-path:polygon(0_0,100%_0,100%_100%,0_100%,14px_50%)] motion-reduce:before:transition-none max-[560px]:h-[46px] flex-1 max-[560px]:w-[60px] max-[560px]:flex-none max-[560px]:first:w-[50px] text-ck-muted before:bg-ck-stone"><span class="flex min-w-0 flex-1 items-center justify-center gap-2 rounded-md whitespace-nowrap"><span class="grid size-6 flex-none place-items-center rounded-full border-[1.5px] border-current text-[.76rem] font-bold">3</span><span class="max-[560px]:sr-only">Payment</span></span></li>
        <li class="relative isolate flex h-[50px] min-w-0 px-3.5 text-[.92rem] not-first:-ml-2.5 first:pl-0 last:pr-0 before:absolute before:inset-0 before:-z-10 before:transition-colors before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%,14px_50%)] first:before:rounded-l-[10px] first:before:[clip-path:polygon(0_0,calc(100%_-_14px)_0,100%_50%,calc(100%_-_14px)_100%,0_100%)] last:before:rounded-r-[10px] last:before:[clip-path:polygon(0_0,100%_0,100%_100%,0_100%,14px_50%)] motion-reduce:before:transition-none max-[560px]:h-[46px] flex-1 max-[560px]:w-[60px] max-[560px]:flex-none max-[560px]:first:w-[50px] text-ck-muted before:bg-ck-stone"><span class="flex min-w-0 flex-1 items-center justify-center gap-2 rounded-md whitespace-nowrap"><span class="grid size-6 flex-none place-items-center rounded-full border-[1.5px] border-current text-[.76rem] font-bold">4</span><span class="max-[560px]:sr-only">Review</span></span></li>
      </ol>
    </nav>
  </div>
  <div class="rounded-2xl border border-ck-rule bg-white shadow-[0_1px_2px_rgba(28,25,23,.05),0_12px_28px_-18px_rgba(124,45,18,.22)] px-[22px] py-3.5 max-[560px]:px-4 max-[560px]:py-3">
    <nav aria-label="Checkout progress">
      <ol class="flex flex-wrap items-center gap-x-3 gap-y-2 text-[.9rem] text-ck-muted max-[560px]:gap-x-2 max-[560px]:gap-y-1.5 max-[560px]:text-[.84rem]">
        <li class="flex items-center gap-2 max-[560px]:gap-1.5"><a class="inline-flex items-center gap-2 rounded font-semibold text-ck-dark underline decoration-[rgba(154,52,18,.35)] underline-offset-4 hover:decoration-current focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ck-accent" href="#"><span class="grid size-[22px] flex-none place-items-center rounded-full border-[1.5px] text-[.72rem] font-bold max-[560px]:size-5 border-ck-soft bg-ck-soft"><svg class="size-[13px] flex-none fill-none stroke-current stroke-3" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Cart<span class="sr-only">, completed</span></a><span class="ml-1 font-normal text-[#78716c] max-[560px]:ml-0.5" aria-hidden="true">/</span></li>
        <li class="flex items-center gap-2 max-[560px]:gap-1.5"><a class="inline-flex items-center gap-2 rounded font-semibold text-ck-dark underline decoration-[rgba(154,52,18,.35)] underline-offset-4 hover:decoration-current focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ck-accent" href="#"><span class="grid size-[22px] flex-none place-items-center rounded-full border-[1.5px] text-[.72rem] font-bold max-[560px]:size-5 border-ck-soft bg-ck-soft"><svg class="size-[13px] flex-none fill-none stroke-current stroke-3" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="sr-only">, completed</span></a><span class="ml-1 font-normal text-[#78716c] max-[560px]:ml-0.5" aria-hidden="true">/</span></li>
        <li class="flex items-center gap-2 max-[560px]:gap-1.5 font-semibold text-ck-ink" aria-current="step"><span class="grid size-[22px] flex-none place-items-center rounded-full border-[1.5px] text-[.72rem] font-bold max-[560px]:size-5 border-ck-accent bg-ck-accent text-white">3</span>Payment<span class="ml-1 font-normal text-[#78716c] max-[560px]:ml-0.5" aria-hidden="true">/</span></li>
        <li class="flex items-center gap-2 max-[560px]:gap-1.5"><span class="grid size-[22px] flex-none place-items-center rounded-full border-[1.5px] text-[.72rem] font-bold max-[560px]:size-5 border-current">4</span>Review</li>
      </ol>
    </nav>
  </div>
</div></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-ck-muted uppercase">Single-page checkout</span>
<form class="grid items-start gap-6 min-[992px]:grid-cols-[2fr_1fr]" data-wizard data-subtotal="121" aria-labelledby="co-title">
  <div class="rounded-2xl border border-ck-rule bg-white shadow-[0_1px_2px_rgba(28,25,23,.05),0_12px_28px_-18px_rgba(124,45,18,.22)] min-w-0 px-8 py-7 max-[600px]:px-[18px] max-[600px]:py-6">
    <div class="flex flex-wrap items-center justify-between gap-3"><h2 class="text-[1.35rem] font-bold tracking-[-.015em]" id="co-title">Checkout</h2><span class="inline-flex items-center gap-1.5 text-[.82rem] text-ck-muted"><svg class="size-[15px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Saltnorth Supply · Secure checkout</span></div>
    <ol class="mt-[22px] grid grid-cols-3 gap-2.5 max-[600px]:gap-2" data-stepper aria-label="Progress">
      <li class="group relative flex min-w-0 items-center gap-2.5 pb-3 text-[.9rem] text-ck-muted data-[state=current]:font-semibold data-[state=current]:text-ck-ink data-[state=done]:text-ck-ink after:absolute after:inset-x-0 after:bottom-0 after:h-[3px] after:rounded-[3px] after:bg-ck-track before:absolute before:bottom-0 before:left-0 before:z-[1] before:h-[3px] before:w-0 before:rounded-[3px] before:bg-ck-accent before:transition-[width] before:duration-350 before:ease-[ease] data-[state=current]:before:w-1/2 data-[state=done]:before:w-full motion-reduce:before:transition-none max-[600px]:gap-[7px] max-[600px]:text-[.8rem]"><span class="grid h-[26px] min-w-7 place-items-center rounded-[7px] bg-ck-stone px-1 text-[.78rem] font-bold tracking-[.03em] tabular-nums transition-colors duration-250 group-data-[state=current]:bg-ck-accent group-data-[state=current]:text-white group-data-[state=done]:bg-ck-soft group-data-[state=done]:text-ck-dark motion-reduce:transition-none max-[600px]:h-6 max-[600px]:min-w-6"><b class="group-data-[state=done]:hidden">01</b><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-data-[state=done]:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Shipping<span class="sr-only" data-sr></span></li>
      <li class="group relative flex min-w-0 items-center gap-2.5 pb-3 text-[.9rem] text-ck-muted data-[state=current]:font-semibold data-[state=current]:text-ck-ink data-[state=done]:text-ck-ink after:absolute after:inset-x-0 after:bottom-0 after:h-[3px] after:rounded-[3px] after:bg-ck-track before:absolute before:bottom-0 before:left-0 before:z-[1] before:h-[3px] before:w-0 before:rounded-[3px] before:bg-ck-accent before:transition-[width] before:duration-350 before:ease-[ease] data-[state=current]:before:w-1/2 data-[state=done]:before:w-full motion-reduce:before:transition-none max-[600px]:gap-[7px] max-[600px]:text-[.8rem]"><span class="grid h-[26px] min-w-7 place-items-center rounded-[7px] bg-ck-stone px-1 text-[.78rem] font-bold tracking-[.03em] tabular-nums transition-colors duration-250 group-data-[state=current]:bg-ck-accent group-data-[state=current]:text-white group-data-[state=done]:bg-ck-soft group-data-[state=done]:text-ck-dark motion-reduce:transition-none max-[600px]:h-6 max-[600px]:min-w-6"><b class="group-data-[state=done]:hidden">02</b><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-data-[state=done]:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Payment<span class="sr-only" data-sr></span></li>
      <li class="group relative flex min-w-0 items-center gap-2.5 pb-3 text-[.9rem] text-ck-muted data-[state=current]:font-semibold data-[state=current]:text-ck-ink data-[state=done]:text-ck-ink after:absolute after:inset-x-0 after:bottom-0 after:h-[3px] after:rounded-[3px] after:bg-ck-track before:absolute before:bottom-0 before:left-0 before:z-[1] before:h-[3px] before:w-0 before:rounded-[3px] before:bg-ck-accent before:transition-[width] before:duration-350 before:ease-[ease] data-[state=current]:before:w-1/2 data-[state=done]:before:w-full motion-reduce:before:transition-none max-[600px]:gap-[7px] max-[600px]:text-[.8rem]"><span class="grid h-[26px] min-w-7 place-items-center rounded-[7px] bg-ck-stone px-1 text-[.78rem] font-bold tracking-[.03em] tabular-nums transition-colors duration-250 group-data-[state=current]:bg-ck-accent group-data-[state=current]:text-white group-data-[state=done]:bg-ck-soft group-data-[state=done]:text-ck-dark motion-reduce:transition-none max-[600px]:h-6 max-[600px]:min-w-6"><b class="group-data-[state=done]:hidden">03</b><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-data-[state=done]:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Review<span class="sr-only" data-sr></span></li>
    </ol>

    <section class="mt-[26px] grid animate-ck-in gap-4 motion-reduce:animate-none" data-step aria-labelledby="co-h1">
      <h3 class="text-[1.12rem] font-bold tracking-[-.01em] focus:outline-none" id="co-h1" tabindex="-1"><span class="mb-0.5 block text-[.72rem] font-bold tracking-[.1em] text-ck-dark uppercase">Step 1 of 3</span>Where should we send it?</h3>
      <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-name">Full name</label>
        <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-name" name="name" required autocomplete="name" value="Maya Okafor"></div>
      <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-street">Street address</label>
        <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-street" name="street" required autocomplete="street-address" value="418 Alder Street, Apt 3"></div>
      <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-3.5">
        <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-city">City</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-city" name="city" required autocomplete="address-level2" value="Portland"></div>
        <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-zip">Postcode</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-zip" name="postcode" required autocomplete="postal-code" value="97205"></div>
        <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-country">Country</label>
          <select class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-country" name="country" autocomplete="country-name"><option>United States</option><option>Canada</option><option>United Kingdom</option><option>Ireland</option><option>Australia</option></select></div>
      </div>
      <fieldset class="grid gap-1.5"><legend class="mb-1.5 text-[.88rem] font-semibold">Delivery</legend>
        <div class="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-3">
          <label class="flex cursor-pointer items-start gap-3 rounded-xl border-[1.5px] border-ck-field px-4 py-3.5 transition-colors has-checked:border-ck-accent has-checked:bg-ck-tint motion-reduce:transition-none"><input class="mt-0.5 size-[18px] flex-none accent-ck-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ck-accent" type="radio" name="delivery" value="Standard, 3–5 business days" data-cost="0" required><span class="grid flex-1 gap-0.5"><b class="text-[.95rem]">Standard</b><span class="text-[.82rem] text-ck-muted">3–5 business days</span></span><em class="text-[.92rem] font-bold not-italic">Free</em></label>
          <label class="flex cursor-pointer items-start gap-3 rounded-xl border-[1.5px] border-ck-field px-4 py-3.5 transition-colors has-checked:border-ck-accent has-checked:bg-ck-tint motion-reduce:transition-none"><input class="mt-0.5 size-[18px] flex-none accent-ck-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ck-accent" type="radio" name="delivery" value="Express, next business day" data-cost="12" checked><span class="grid flex-1 gap-0.5"><b class="text-[.95rem]">Express</b><span class="text-[.82rem] text-ck-muted">Next business day</span></span><em class="text-[.92rem] font-bold not-italic">$12.00</em></label>
        </div></fieldset>
    </section>

    <section class="mt-[26px] grid animate-ck-in gap-4 motion-reduce:animate-none" data-step aria-labelledby="co-h2">
      <h3 class="text-[1.12rem] font-bold tracking-[-.01em] focus:outline-none" id="co-h2" tabindex="-1"><span class="mb-0.5 block text-[.72rem] font-bold tracking-[.1em] text-ck-dark uppercase">Step 2 of 3</span>How would you like to pay?</h3>
      <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-card">Card number</label>
        <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-card" name="card" required inputmode="numeric" autocomplete="cc-number" pattern="(?:[0-9] ?){12,18}[0-9]" maxlength="23" aria-describedby="co-card-hint" placeholder="1234 5678 9012 3456" value="4242 4242 4242 4242">
        <span class="text-[.8rem] text-ck-muted" id="co-card-hint">13 to 19 digits, spaces are fine.</span></div>
      <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-3.5">
        <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-exp">Expiry date</label>
          <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-exp" name="expiry" required inputmode="numeric" autocomplete="cc-exp" pattern="(0[1-9]|1[0-2]) ?/ ?[0-9]{2}" maxlength="7" aria-describedby="co-exp-hint" placeholder="MM/YY" value="08/29">
          <span class="text-[.8rem] text-ck-muted" id="co-exp-hint">MM/YY</span></div>
        <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-cvc">Security code</label>
          <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-cvc" name="cvc" required inputmode="numeric" autocomplete="cc-csc" pattern="[0-9]{3,4}" maxlength="4" aria-describedby="co-cvc-hint" value="314">
          <span class="text-[.8rem] text-ck-muted" id="co-cvc-hint">3 or 4 digits on the back of the card.</span></div>
      </div>
      <div class="grid min-w-0 content-start gap-1.5"><label class="text-[.88rem] font-semibold" for="co-holder">Name on card</label>
        <input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-ck-field bg-white px-3 py-2.5 text-[.95rem] placeholder:text-[#6f6862] focus-visible:border-ck-accent focus-visible:shadow-[0_0_0_4px_var(--color-ck-soft)] focus-visible:outline-none" id="co-holder" name="holder" required autocomplete="cc-name" value="Maya Okafor"></div>
      <label class="flex cursor-pointer items-start gap-2.5 text-[.92rem]"><input class="mt-0.5 size-[18px] flex-none accent-ck-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ck-accent" type="checkbox" name="billing" value="same" checked>Billing address same as shipping</label>
    </section>

    <section class="mt-[26px] grid animate-ck-in gap-4 motion-reduce:animate-none" data-step aria-labelledby="co-h3">
      <h3 class="text-[1.12rem] font-bold tracking-[-.01em] focus:outline-none" id="co-h3" tabindex="-1"><span class="mb-0.5 block text-[.72rem] font-bold tracking-[.1em] text-ck-dark uppercase">Step 3 of 3</span>Check and pay</h3>
      <dl class="grid divide-y divide-ck-rule overflow-hidden rounded-xl border border-ck-rule text-[.92rem]">
        <div class="flex justify-between gap-4 px-3.5 py-[11px]"><dt class="flex-none text-ck-muted">Name</dt><dd class="text-right font-semibold wrap-anywhere" data-out="name">Maya Okafor</dd></div>
        <div class="flex justify-between gap-4 px-3.5 py-[11px]"><dt class="flex-none text-ck-muted">Ship to</dt><dd class="text-right font-semibold wrap-anywhere"><span data-out="street">418 Alder Street, Apt 3</span>, <span data-out="city">Portland</span> <span data-out="postcode">97205</span>, <span data-out="country">United States</span></dd></div>
        <div class="flex justify-between gap-4 px-3.5 py-[11px]"><dt class="flex-none text-ck-muted">Delivery</dt><dd class="text-right font-semibold wrap-anywhere" data-out="delivery">Express, next business day</dd></div>
        <div class="flex justify-between gap-4 px-3.5 py-[11px]"><dt class="flex-none text-ck-muted">Payment</dt><dd class="text-right font-semibold wrap-anywhere">Card ending <span data-out-last4="card">4242</span></dd></div>
      </dl>
    </section>

    <section class="mt-[26px] grid animate-ck-in justify-items-center gap-4 pt-3 pb-1 text-center motion-reduce:animate-none" data-done hidden aria-labelledby="co-h4">
      <span class="grid size-14 place-items-center rounded-full bg-ck-soft text-ck-dark"><svg class="size-[26px] flex-none fill-none stroke-current stroke-3" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
      <h3 class="text-[1.12rem] font-bold tracking-[-.01em] focus:outline-none" id="co-h4" tabindex="-1">Order SN-40718 confirmed</h3>
      <p class="max-w-[40ch] text-[.92rem] text-ck-muted">Thank you, Maya. Your parcel is being packed and tracking details follow as soon as it ships.</p>
      <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] px-[22px] text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ck-accent)] focus-visible:outline-none motion-reduce:transition-none border-ck-field bg-white text-ck-ink hover:bg-ck-tint" data-restart>Start a new order</button>
    </section>

    <div class="mt-[26px] flex gap-2.5 border-t border-ck-rule pt-5">
      <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] px-[22px] text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ck-accent)] focus-visible:outline-none motion-reduce:transition-none border-ck-field bg-white text-ck-ink hover:bg-ck-tint" data-back hidden>Back</button>
      <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] px-[22px] text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ck-accent)] focus-visible:outline-none motion-reduce:transition-none ms-auto border-ck-accent bg-ck-accent text-white hover:border-ck-dark hover:bg-ck-dark" data-next hidden>Continue</button>
      <button type="submit" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] px-[22px] text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ck-accent)] focus-visible:outline-none motion-reduce:transition-none ms-auto border-ck-accent bg-ck-accent text-white hover:border-ck-dark hover:bg-ck-dark"><svg class="size-[15px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg><span>Pay <span data-total>$133.00</span></span></button>
    </div>
  </div>

  <aside class="rounded-2xl border border-ck-rule bg-white shadow-[0_1px_2px_rgba(28,25,23,.05),0_12px_28px_-18px_rgba(124,45,18,.22)] p-6 max-[600px]:px-[18px] max-[600px]:py-5 min-[992px]:sticky min-[992px]:top-5" aria-labelledby="co-sum">
    <h3 class="mb-3.5 text-base font-bold" id="co-sum">Order summary</h3>
    <ul class="grid gap-3.5 border-b border-ck-rule pb-4">
      <li class="flex items-center gap-3 text-[.9rem]"><span class="grid size-[52px] flex-none place-items-center rounded-xl bg-[linear-gradient(135deg,#e6d6b8,#c2a878)] text-white/90" aria-hidden="true"><svg class="size-[26px] fill-none stroke-current stroke-[1.6]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M8.5 3.5 4 6 2.5 10l3 1.2L7 9.8V20.5h10V9.8l1.5 1.4 3-1.2L20 6l-4.5-2.5c-.7 1.3-2 2-3.5 2s-2.8-.7-3.5-2Z"/></svg></span><span class="grid min-w-0 flex-1"><b class="font-semibold">Linen Overshirt</b><small class="text-[.82rem] text-ck-muted">Sand, M · Qty 1</small></span><span class="font-semibold tabular-nums">$89.00</span></li>
      <li class="flex items-center gap-3 text-[.9rem]"><span class="grid size-[52px] flex-none place-items-center rounded-xl bg-[linear-gradient(135deg,#6b6561,#35312f)] text-white/90" aria-hidden="true"><svg class="size-[26px] fill-none stroke-current stroke-[1.6]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M5 14a7 7 0 0 1 14 0M4 14h16v5.5H4zM8.5 14v5.5M12 14v5.5M15.5 14v5.5"/><circle cx="12" cy="5" r="1.8"/></svg></span><span class="grid min-w-0 flex-1"><b class="font-semibold">Merino Beanie</b><small class="text-[.82rem] text-ck-muted">Charcoal · Qty 1</small></span><span class="font-semibold tabular-nums">$32.00</span></li>
    </ul>
    <dl class="grid gap-2 pt-3.5 text-[.92rem]">
      <div class="flex justify-between gap-3"><dt class="text-ck-muted">Subtotal</dt><dd class="tabular-nums">$121.00</dd></div>
      <div class="flex justify-between gap-3"><dt class="text-ck-muted">Shipping</dt><dd class="tabular-nums" data-ship>$12.00</dd></div>
      <div class="mt-1.5 flex justify-between gap-3 border-t border-ck-rule pt-3 text-[1.05rem] font-bold" aria-live="polite" aria-atomic="true"><dt>Total</dt><dd class="tabular-nums" data-total>$133.00</dd></div>
    </dl>
  </aside>
</form></div>
CSS
@theme {
  --color-ck-accent: #c2410c;
  --color-ck-dark: #9a3412;
  --color-ck-soft: #ffedd5;
  --color-ck-tint: #fff7ed;
  --color-ck-ink: #1c1917;
  --color-ck-muted: #57534e;
  --color-ck-field: #8f867e;
  --color-ck-track: #e2dcd4;
  --color-ck-rule: #e7e2da;
  --color-ck-stone: #efebe5;
  --animate-ck-in: ck-in .3s ease;
  @keyframes ck-in { from { opacity: 0; transform: translateY(6px); } }
}
JavaScript
// Form wizard: shows one step at a time, marks the stepper with data-state and aria-current="step",
// checks the step's fields before moving on and moves focus to the new step's heading.
// Checkout: the delivery choice ([data-cost]) updates [data-ship] and every [data-total]; [data-out-last4] shows only a card's last four digits.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
  }
  function price() {
    if (!wz.dataset.subtotal) return;
    var d = wz.querySelector('[data-cost]:checked'), c = d ? +d.dataset.cost : 0;
    wz.querySelectorAll('[data-ship]').forEach(function (o) { o.textContent = c ? '$' + c.toFixed(2) : 'Free'; });
    wz.querySelectorAll('[data-total]').forEach(function (o) { o.textContent = '$' + (+wz.dataset.subtotal + c).toFixed(2); });
  }
  function go(i, focus) {
    at = i; mark(i); price();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    wz.querySelectorAll('[data-out-last4]').forEach(function (o) {
      var f = wz.elements[o.dataset.outLast4]; o.textContent = f ? f.value.replace(/\D/g, '').slice(-4) : '';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  wz.noValidate = true;
  wz.addEventListener('change', price);
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

About this set

Two checkout patterns in a warm stone and burnt-orange palette. Progress for a multi-page checkout is a static trail for stores that put Cart, Shipping, Payment and Review on separate pages. It comes in two styles: chevron segments cut with clip-path, and a slim line with small numbered circles. Completed steps are links with a check icon, the current step carries aria-current=”step” and upcoming steps are plain text, with no JavaScript at all. On a phone the chevrons shrink to icons and numbers and keep only the current label. The single-page checkout is a three-step form wizard, Shipping, Payment and Review, beside an order summary that stacks under the form on narrow screens. Choosing Standard or Express delivery updates the shipping line, the total and the Pay button text. The payment step uses the right autocomplete tokens, numeric keyboards and patterns for card number, expiry and security code, and the review shows only the card’s last four digits. A small vanilla script shows one step at a time, checks each step with the browser’s own validation before moving on and moves focus to the new step’s heading. Without JavaScript every step shows and the Pay button submits the form normally.

What’s included

  • Chevron and slim numbered progress trails for multi-page checkouts, no JavaScript
  • Single-page Shipping, Payment and Review wizard with an order summary
  • Delivery choice updates shipping, total and the Pay button text
  • Card fields with cc-* autocomplete, numeric keyboards and format patterns
  • Review shows only the card's last four digits
  • Works without JavaScript: all steps show and the form submits normally

Accessibility

Both progress trails are nav landmarks with an ordered list: completed steps are links that announce as completed, the current step has aria-current="step" and upcoming steps are plain text at 4.5:1. The wizard stepper updates aria-current and visually hidden completed text, focus moves to each new step's heading, which starts with Step 2 of 3, and the order total is announced politely when the delivery choice changes. Every link, field and button has a visible focus style, field borders reach 3:1, and transitions and the step animation are switched off under prefers-reduced-motion.

Customise it

Change the --ck-accent, --ck-dark, --ck-soft and --ck-tint custom properties in the plain and Bootstrap versions (Bootstrap buttons and fields read them through --bs-btn-* and --bs-border-color), or the --color-ck-* values in the Tailwind @theme block. Set data-subtotal on the form and data-cost on each delivery option to match your prices.