Open demo

CSS code

HTML
<nav class="stp stp-h" aria-label="Checkout progress">
  <ol>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b><span class="stp-sr">Completed: </span>Basket</b><small>3 items</small></a></li>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b><span class="stp-sr">Completed: </span>Delivery</b><small>Standard</small></a></li>
    <li aria-current="step"><div class="stp-i"><span class="stp-dot">3</span><b>Payment</b><small>In progress</small></div></li>
    <li><div class="stp-i"><span class="stp-dot">4</span><b>Confirm</b><small>Review order</small></div></li>
  </ol>
</nav>

<nav class="stp stp-v" aria-label="Setup progress">
  <ol>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span class="stp-txt"><b><span class="stp-sr">Completed: </span>Create your workspace</b><span>Named, and the region picked.</span></span></a></li>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span class="stp-txt"><b><span class="stp-sr">Completed: </span>Invite your team</b><span>4 invitations sent.</span></span></a></li>
    <li aria-current="step"><div class="stp-i"><span class="stp-dot">3</span>
      <span class="stp-txt"><b>Connect a repository</b><span>Pick the repo the board should track.</span></span></div></li>
    <li><div class="stp-i"><span class="stp-dot">4</span>
      <span class="stp-txt"><b>Set up your first board</b><span>Takes about two minutes.</span></span></div></li>
  </ol>
</nav>
CSS
/* Step navigation: an ordered list in a labelled <nav>. Completed steps are links back to that step and carry
   visually hidden "Completed" text (the tick alone is not announced); the current step has aria-current="step". */
.stp{--stp-accent:#4f46e5;--stp-line:#e0e4ec;--stp-ink:#101828;--stp-done:#475467;--stp-todo:#667085;--stp-ring:#eef2ff;width:100%}
.stp ol{margin:0;padding:0;list-style:none}
.stp a{color:inherit;text-decoration:none;border-radius:10px}
.stp a:hover b{text-decoration:underline}
.stp a:focus-visible{outline:2px solid var(--stp-accent);outline-offset:4px}
.stp-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.stp-dot{position:relative;z-index:1;display:grid;place-items:center;flex-shrink:0;width:36px;height:36px;border-radius:50%;
  background:#fff;border:2px solid var(--stp-line);color:var(--stp-todo);font-size:.85rem;font-weight:800}
.stp-dot svg{display:block;width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:3}
.stp .done .stp-dot{background:var(--stp-accent);border-color:var(--stp-accent);color:#fff}
.stp [aria-current] .stp-dot{border-color:var(--stp-accent);color:var(--stp-accent);box-shadow:0 0 0 4px var(--stp-ring)}
.stp b{font-weight:700;color:var(--stp-todo)}
.stp .done b{color:var(--stp-done)}
.stp [aria-current] b{color:var(--stp-ink)}
/* horizontal */
.stp-h{max-width:640px}
.stp-h ol{display:flex;align-items:flex-start}
.stp-h li{position:relative;flex:1}
.stp-h li::before{content:"";position:absolute;top:17px;left:-50%;width:100%;height:2px;background:var(--stp-line)}
.stp-h li:first-child::before{display:none}
.stp-h li.done::before,.stp-h li[aria-current]::before{background:var(--stp-accent)}
.stp-h .stp-i{display:flex;flex-direction:column;align-items:center;text-align:center}
.stp-h b{margin-top:10px;font-size:.85rem}
.stp-h small{margin-top:2px;font-size:.76rem;color:var(--stp-todo)}
/* vertical */
.stp-v{max-width:340px}
.stp-v li{position:relative;padding-bottom:26px}
.stp-v li:last-child{padding-bottom:0}
.stp-v li::before{content:"";position:absolute;left:17px;top:36px;bottom:0;width:2px;background:var(--stp-line)}
.stp-v li:last-child::before{display:none}
.stp-v li.done::before{background:var(--stp-accent)}
.stp-v .stp-i{display:flex;gap:15px}
.stp-v b{display:block;font-size:.9rem}
.stp-v .done b,.stp-v [aria-current] b{color:var(--stp-ink)}
.stp-v .stp-txt>span{display:block;margin-top:3px;font-size:.81rem;line-height:1.5;color:var(--stp-todo)}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<nav class="stp stp-h w-100" aria-label="Checkout progress">
  <ol class="list-unstyled m-0 d-flex align-items-start">
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot d-grid rounded-circle fw-bolder"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b><span class="visually-hidden">Completed: </span>Basket</b><small>3 items</small></a></li>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot d-grid rounded-circle fw-bolder"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b><span class="visually-hidden">Completed: </span>Delivery</b><small>Standard</small></a></li>
    <li aria-current="step"><div class="stp-i"><span class="stp-dot d-grid rounded-circle fw-bolder">3</span><b>Payment</b><small>In progress</small></div></li>
    <li><div class="stp-i"><span class="stp-dot d-grid rounded-circle fw-bolder">4</span><b>Confirm</b><small>Review order</small></div></li>
  </ol>
</nav>

<nav class="stp stp-v w-100" aria-label="Setup progress">
  <ol class="list-unstyled m-0">
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot d-grid rounded-circle fw-bolder"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span class="stp-txt"><b><span class="visually-hidden">Completed: </span>Create your workspace</b><span>Named, and the region picked.</span></span></a></li>
    <li class="done"><a class="stp-i" href="#"><span class="stp-dot d-grid rounded-circle fw-bolder"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span class="stp-txt"><b><span class="visually-hidden">Completed: </span>Invite your team</b><span>4 invitations sent.</span></span></a></li>
    <li aria-current="step"><div class="stp-i"><span class="stp-dot d-grid rounded-circle fw-bolder">3</span>
      <span class="stp-txt"><b>Connect a repository</b><span>Pick the repo the board should track.</span></span></div></li>
    <li><div class="stp-i"><span class="stp-dot d-grid rounded-circle fw-bolder">4</span>
      <span class="stp-txt"><b>Set up your first board</b><span>Takes about two minutes.</span></span></div></li>
  </ol>
</nav>
CSS
/* Step navigation built from Bootstrap utilities (.list-unstyled, .d-flex, .rounded-circle, .visually-hidden) plus a few
   rules for the connector lines. Completed steps are links back to that step; the current step has aria-current="step". */
.stp{--stp-accent:#4f46e5;--stp-line:#e0e4ec;--stp-ink:#101828;--stp-done:#475467;--stp-todo:#667085;--stp-ring:#eef2ff}
.stp a{color:inherit;text-decoration:none;border-radius:10px}
.stp a:hover b{text-decoration:underline}
.stp a:focus-visible{outline:2px solid var(--stp-accent);outline-offset:4px;box-shadow:none}
.stp-dot{position:relative;z-index:1;place-items:center;flex-shrink:0;width:36px;height:36px;background:#fff;border:2px solid var(--stp-line);
  color:var(--stp-todo);font-size:.85rem}
.stp-dot svg{display:block;width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:3}
.stp .done .stp-dot{background:var(--stp-accent);border-color:var(--stp-accent);color:#fff}
.stp [aria-current] .stp-dot{border-color:var(--stp-accent);color:var(--stp-accent);box-shadow:0 0 0 4px var(--stp-ring)}
.stp b{font-weight:700;color:var(--stp-todo)}
.stp .done b{color:var(--stp-done)}
.stp [aria-current] b{color:var(--stp-ink)}
/* horizontal */
.stp-h{max-width:640px}
.stp-h li{position:relative;flex:1}
.stp-h li::before{content:"";position:absolute;top:17px;left:-50%;width:100%;height:2px;background:var(--stp-line)}
.stp-h li:first-child::before{display:none}
.stp-h li.done::before,.stp-h li[aria-current]::before{background:var(--stp-accent)}
.stp-h .stp-i{display:flex;flex-direction:column;align-items:center;text-align:center}
.stp-h b{margin-top:10px;font-size:.85rem}
.stp-h small{margin-top:2px;font-size:.76rem;color:var(--stp-todo)}
/* vertical */
.stp-v{max-width:340px}
.stp-v li{position:relative;padding-bottom:26px}
.stp-v li:last-child{padding-bottom:0}
.stp-v li::before{content:"";position:absolute;left:17px;top:36px;bottom:0;width:2px;background:var(--stp-line)}
.stp-v li:last-child::before{display:none}
.stp-v li.done::before{background:var(--stp-accent)}
.stp-v .stp-i{display:flex;gap:15px}
.stp-v b{display:block;font-size:.9rem}
.stp-v .done b,.stp-v [aria-current] b{color:var(--stp-ink)}
.stp-v .stp-txt>span{display:block;margin-top:3px;font-size:.81rem;line-height:1.5;color:var(--stp-todo)}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<nav class="w-full max-w-[640px]" aria-label="Checkout progress">
  <ol class="flex items-start">
    <li class="relative flex-1 before:absolute before:top-[17px] before:left-[-50%] before:h-0.5 before:w-full first:before:hidden before:bg-[#4f46e5]"><a class="group flex flex-col items-center text-center rounded-[10px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#4f46e5]" href="#"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-[#4f46e5] text-white"><svg class="block size-4 fill-none stroke-current stroke-3" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b class="mt-2.5 text-[.85rem] font-bold text-[#475467] group-hover:underline"><span class="sr-only">Completed: </span>Basket</b><small class="mt-0.5 text-[.76rem] text-[#667085]">3 items</small></a></li>
    <li class="relative flex-1 before:absolute before:top-[17px] before:left-[-50%] before:h-0.5 before:w-full first:before:hidden before:bg-[#4f46e5]"><a class="group flex flex-col items-center text-center rounded-[10px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#4f46e5]" href="#"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-[#4f46e5] text-white"><svg class="block size-4 fill-none stroke-current stroke-3" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span><b class="mt-2.5 text-[.85rem] font-bold text-[#475467] group-hover:underline"><span class="sr-only">Completed: </span>Delivery</b><small class="mt-0.5 text-[.76rem] text-[#667085]">Standard</small></a></li>
    <li class="relative flex-1 before:absolute before:top-[17px] before:left-[-50%] before:h-0.5 before:w-full first:before:hidden before:bg-[#4f46e5]" aria-current="step"><div class="flex flex-col items-center text-center"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-white text-[#4f46e5] shadow-[0_0_0_4px_#eef2ff]">3</span><b class="mt-2.5 text-[.85rem] font-bold text-[#101828]">Payment</b><small class="mt-0.5 text-[.76rem] text-[#667085]">In progress</small></div></li>
    <li class="relative flex-1 before:absolute before:top-[17px] before:left-[-50%] before:h-0.5 before:w-full first:before:hidden before:bg-[#e0e4ec]"><div class="flex flex-col items-center text-center"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#e0e4ec] bg-white text-[#667085]">4</span><b class="mt-2.5 text-[.85rem] font-bold text-[#667085]">Confirm</b><small class="mt-0.5 text-[.76rem] text-[#667085]">Review order</small></div></li>
  </ol>
</nav>

<nav class="w-full max-w-[340px]" aria-label="Setup progress">
  <ol>
    <li class="relative pb-[26px] last:pb-0 before:absolute before:top-9 before:bottom-0 before:left-[17px] before:w-0.5 last:before:hidden before:bg-[#4f46e5]"><a class="group flex gap-[15px] rounded-[10px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#4f46e5]" href="#"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-[#4f46e5] text-white"><svg class="block size-4 fill-none stroke-current stroke-3" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span><b class="block text-[.9rem] text-[#101828] group-hover:underline"><span class="sr-only">Completed: </span>Create your workspace</b><span class="mt-[3px] block text-[.81rem] leading-normal text-[#667085]">Named, and the region picked.</span></span></a></li>
    <li class="relative pb-[26px] last:pb-0 before:absolute before:top-9 before:bottom-0 before:left-[17px] before:w-0.5 last:before:hidden before:bg-[#4f46e5]"><a class="group flex gap-[15px] rounded-[10px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#4f46e5]" href="#"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-[#4f46e5] text-white"><svg class="block size-4 fill-none stroke-current stroke-3" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg></span>
      <span><b class="block text-[.9rem] text-[#101828] group-hover:underline"><span class="sr-only">Completed: </span>Invite your team</b><span class="mt-[3px] block text-[.81rem] leading-normal text-[#667085]">4 invitations sent.</span></span></a></li>
    <li class="relative pb-[26px] last:pb-0 before:absolute before:top-9 before:bottom-0 before:left-[17px] before:w-0.5 last:before:hidden before:bg-[#e0e4ec]" aria-current="step"><div class="flex gap-[15px]"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#4f46e5] bg-white text-[#4f46e5] shadow-[0_0_0_4px_#eef2ff]">3</span>
      <span><b class="block text-[.9rem] text-[#101828]">Connect a repository</b><span class="mt-[3px] block text-[.81rem] leading-normal text-[#667085]">Pick the repo the board should track.</span></span></div></li>
    <li class="relative pb-[26px] last:pb-0 before:absolute before:top-9 before:bottom-0 before:left-[17px] before:w-0.5 last:before:hidden before:bg-[#e0e4ec]"><div class="flex gap-[15px]"><span class="relative z-1 grid size-9 shrink-0 place-items-center rounded-full border-2 text-[.85rem] font-extrabold border-[#e0e4ec] bg-white text-[#667085]">4</span>
      <span><b class="block text-[.9rem] text-[#667085]">Set up your first board</b><span class="mt-[3px] block text-[.81rem] leading-normal text-[#667085]">Takes about two minutes.</span></span></div></li>
  </ol>
</nav>

About this set

Two progress indicators for multi-step flows. The horizontal one is a four-step checkout (Basket, Delivery, Payment, Confirm) with numbered circles joined by a line that turns indigo up to the current step, and a short status under each label. The vertical one is a setup checklist with a title and a sentence per step, joined by a line down the left. Completed steps show a tick on a filled circle, the current step has an outlined circle with a soft halo, and upcoming steps stay grey. Use the horizontal version above a checkout or sign-up form and the vertical one for onboarding or a settings wizard. Each is an ordered list inside a labelled nav. Completed steps are links, so people can go back and change an earlier answer; the current step has aria-current=”step”; upcoming steps are plain text because they cannot be reached yet. The tick icon is aria-hidden and each completed step carries visually hidden “Completed:” text, so the state is announced as well as drawn. The connector lines are CSS pseudo-elements and no JavaScript is involved.

What’s included

  • Horizontal checkout stepper and vertical setup checklist
  • Completed steps link back; the current step has aria-current="step"
  • Visually hidden "Completed" text alongside each tick
  • Connector lines drawn with ::before, no JavaScript
  • Bootstrap version uses .list-unstyled, .rounded-circle and .visually-hidden

Accessibility

Each stepper is an ordered list in a nav with its own label, so screen readers announce how many steps there are. Completed steps are links with hidden "Completed:" text, the current step has aria-current="step", and upcoming steps are text only. Links show an indigo focus outline. Nothing animates.

Customise it

Change --stp-accent, --stp-line, --stp-ring and the text colours --stp-ink, --stp-done and --stp-todo on .stp. The dots are 36px (.stp-dot) and the connector offsets (top:17px, left:17px) sit at half that. In Tailwind edit #4f46e5 and #e0e4ec in the before: and border utilities.