Open demo

CSS code

HTML
<div class="ct">
  <div class="head"><b>Segmented bar</b><span>Step 3 of 4</span></div>
  <ol class="mini">
    <li class="on"><span class="seg"></span><span class="lb">Placed<span class="sr"> (done)</span></span></li>
    <li class="on"><span class="seg"></span><span class="lb">Packed<span class="sr"> (done)</span></span></li>
    <li class="cur" aria-current="step"><span class="seg"></span><span class="lb">Transit<span class="sr"> (current step)</span></span></li>
    <li><span class="seg"></span><span class="lb">Delivered<span class="sr"> (to do)</span></span></li>
  </ol>
</div>

<div class="ct">
  <div class="head"><b>Dot connector</b><span>Out for delivery</span></div>
  <div class="dots">
    <ol>
      <li class="on"><i aria-hidden="true"></i><span class="line" aria-hidden="true"></span><span class="sr">Placed (done)</span></li>
      <li class="on"><i aria-hidden="true"></i><span class="line" aria-hidden="true"></span><span class="sr">Packed (done)</span></li>
      <li class="cur" aria-current="step"><i aria-hidden="true"></i><span class="line" aria-hidden="true"></span><span class="sr">In transit (current step)</span></li>
      <li><i aria-hidden="true"></i><span class="sr">Delivered (to do)</span></li>
    </ol>
    <span class="eta">Arrives Thu</span>
  </div>
</div>

<div class="ct">
  <div class="head"><b>Pill row</b><span>For a table cell</span></div>
  <ol class="pillrow">
    <li class="on">Draft<span class="sr"> (done)</span></li>
    <li class="on">Review<span class="sr"> (done)</span></li>
    <li class="cur" aria-current="step">Approved<span class="sr"> (current step)</span></li>
    <li>Live<span class="sr"> (to do)</span></li>
  </ol>
</div>
CSS
/* Three compact trackers. Each is an <ol>; the state is in visually hidden text, the bars and dots are decoration. */
.ct{--ct-done:#16a34a;--ct-now:#4f46e5;--ct-off:#e3e8f2;--ct-ink:#17203a;--ct-muted:#5f6a86;--ct-light:#646f8b;
  background:#fff;border:1px solid #e3e8f2;border-radius:13px;padding:16px 18px}
.ct,.ct *{box-sizing:border-box}
.ct :where(ol,li){margin:0;padding:0;list-style:none}
.ct .head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}
.ct .head b{font-size:.9rem}
.ct .head span{font-size:.77rem;color:var(--ct-muted)}
.ct .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* segmented bar: each step is a segment with its label underneath */
.ct .mini{display:flex}
.ct .mini li{flex:1;display:flex;flex-direction:column;align-items:stretch}
.ct .seg{height:5px;border-radius:99px;background:var(--ct-off);margin:0 3px}
.ct .on .seg{background:var(--ct-done)}
.ct .cur .seg{background:linear-gradient(90deg,var(--ct-now) 60%,var(--ct-off) 60%)}
.ct .mini .lb{margin-top:9px;font-size:.72rem;color:var(--ct-light);text-align:center}
.ct .mini :is(.on,.cur) .lb{color:var(--ct-ink);font-weight:700}
/* dot connector */
.ct .dots{display:flex;align-items:center;gap:7px;font-size:.79rem;color:var(--ct-muted)}
.ct .dots ol{flex:1;display:flex;align-items:center;gap:7px}
.ct .dots li{flex:1;display:flex;align-items:center;gap:7px;position:relative}
.ct .dots li:last-child{flex:none}
.ct .dots i{width:9px;height:9px;border-radius:50%;background:var(--ct-off);flex-shrink:0}
.ct .dots .on i{background:var(--ct-done)}
.ct .dots .cur i{background:var(--ct-now);box-shadow:0 0 0 3px rgba(79,70,229,.18)}
.ct .dots .line{flex:1;height:2px;background:var(--ct-off);min-width:14px}
.ct .dots .on .line{background:var(--ct-done)}
.ct .dots .eta{margin-left:10px}
/* pill row */
.ct .pillrow{display:inline-flex;align-items:center;background:#f1f4fa;border-radius:99px;padding:4px}
.ct .pillrow li{font-size:.75rem;font-weight:700;padding:4px 12px;border-radius:99px;color:var(--ct-muted)}
.ct .pillrow :is(.on,.cur){background:#fff;color:var(--ct-ink);box-shadow:0 1px 3px rgba(23,32,58,.14)}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="ct card"><div class="card-body">
  <div class="head d-flex justify-content-between align-items-baseline" style="margin-bottom:14px"><b>Segmented bar</b><span>Step 3 of 4</span></div>
  <ol class="mini list-unstyled d-flex m-0">
    <li class="on d-flex flex-column"><span class="seg rounded-pill"></span><span class="lb text-center">Placed<span class="visually-hidden"> (done)</span></span></li>
    <li class="on d-flex flex-column"><span class="seg rounded-pill"></span><span class="lb text-center">Packed<span class="visually-hidden"> (done)</span></span></li>
    <li class="cur d-flex flex-column" aria-current="step"><span class="seg rounded-pill"></span><span class="lb text-center">Transit<span class="visually-hidden"> (current step)</span></span></li>
    <li class="d-flex flex-column"><span class="seg rounded-pill"></span><span class="lb text-center">Delivered<span class="visually-hidden"> (to do)</span></span></li>
  </ol>
</div></div>

<div class="ct card"><div class="card-body">
  <div class="head d-flex justify-content-between align-items-baseline" style="margin-bottom:14px"><b>Dot connector</b><span>Out for delivery</span></div>
  <div class="dots d-flex align-items-center">
    <ol class="list-unstyled d-flex align-items-center flex-fill m-0">
      <li class="on d-flex align-items-center"><i class="rounded-circle flex-shrink-0" aria-hidden="true"></i><span class="line flex-fill" aria-hidden="true"></span><span class="visually-hidden">Placed (done)</span></li>
      <li class="on d-flex align-items-center"><i class="rounded-circle flex-shrink-0" aria-hidden="true"></i><span class="line flex-fill" aria-hidden="true"></span><span class="visually-hidden">Packed (done)</span></li>
      <li class="cur d-flex align-items-center" aria-current="step"><i class="rounded-circle flex-shrink-0" aria-hidden="true"></i><span class="line flex-fill" aria-hidden="true"></span><span class="visually-hidden">In transit (current step)</span></li>
      <li class="d-flex align-items-center"><i class="rounded-circle flex-shrink-0" aria-hidden="true"></i><span class="visually-hidden">Delivered (to do)</span></li>
    </ol>
    <span style="margin-left:10px">Arrives Thu</span>
  </div>
</div></div>

<div class="ct card"><div class="card-body">
  <div class="head d-flex justify-content-between align-items-baseline" style="margin-bottom:14px"><b>Pill row</b><span>For a table cell</span></div>
  <ol class="pillrow list-unstyled d-inline-flex align-items-center rounded-pill m-0">
    <li class="on rounded-pill">Draft<span class="visually-hidden"> (done)</span></li>
    <li class="on rounded-pill">Review<span class="visually-hidden"> (done)</span></li>
    <li class="cur rounded-pill" aria-current="step">Approved<span class="visually-hidden"> (current step)</span></li>
    <li class="rounded-pill">Live<span class="visually-hidden"> (to do)</span></li>
  </ol>
</div></div>
CSS
/* Bootstrap cards holding three compact trackers; state is in .visually-hidden text, bars and dots are decoration. */
.ct{--ct-done:#16a34a;--ct-now:#4f46e5;--ct-off:#e3e8f2;--ct-ink:#17203a;--ct-muted:#5f6a86;--ct-light:#646f8b;
  --bs-card-border-color:#e3e8f2;--bs-card-border-radius:13px;--bs-card-spacer-y:16px;--bs-card-spacer-x:18px;--bs-card-color:var(--ct-ink)}
.ct .head b{font-size:.9rem}
.ct .head span{font-size:.77rem;color:var(--ct-muted)}
.ct .seg{height:5px;background:var(--ct-off);margin:0 3px}
.ct .on .seg{background:var(--ct-done)}
.ct .cur .seg{background:linear-gradient(90deg,var(--ct-now) 60%,var(--ct-off) 60%)}
.ct .mini .lb{margin-top:9px;font-size:.72rem;color:var(--ct-light)}
.ct .mini :is(.on,.cur) .lb{color:var(--ct-ink);font-weight:700}
.ct .dots{gap:7px;font-size:.79rem;color:var(--ct-muted)}
.ct .dots ol,.ct .dots li{gap:7px}
.ct .mini li,.ct .dots li{flex:1}
.ct .dots li:last-child{flex:none}
.ct .dots i{width:9px;height:9px;background:var(--ct-off)}
.ct .dots .on i{background:var(--ct-done)}
.ct .dots .cur i{background:var(--ct-now);box-shadow:0 0 0 3px rgba(79,70,229,.18)}
.ct .dots .line{height:2px;background:var(--ct-off);min-width:14px}
.ct .dots .on .line{background:var(--ct-done)}
.ct .pillrow{background:#f1f4fa;padding:4px}
.ct .pillrow li{font-size:.75rem;font-weight:700;padding:4px 12px;color:var(--ct-muted)}
.ct .pillrow :is(.on,.cur){background:#fff;color:var(--ct-ink);box-shadow:0 1px 3px rgba(23,32,58,.14)}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="rounded-[13px] border border-ct-off bg-white px-[18px] py-4 text-ct-ink">
  <div class="mb-3.5 flex items-baseline justify-between"><b class="text-[.9rem]">Segmented bar</b><span class="text-[.77rem] text-ct-muted">Step 3 of 4</span></div>
  <ol class="flex">
    <li class="flex flex-1 flex-col"><span class="mx-[3px] h-[5px] rounded-full bg-ct-done"></span><span class="mt-[9px] text-center text-[.72rem] font-bold text-ct-ink">Placed<span class="sr-only"> (done)</span></span></li>
    <li class="flex flex-1 flex-col"><span class="mx-[3px] h-[5px] rounded-full bg-ct-done"></span><span class="mt-[9px] text-center text-[.72rem] font-bold text-ct-ink">Packed<span class="sr-only"> (done)</span></span></li>
    <li class="flex flex-1 flex-col" aria-current="step"><span class="mx-[3px] h-[5px] rounded-full bg-[linear-gradient(90deg,var(--color-ct-now)_60%,var(--color-ct-off)_60%)]"></span><span class="mt-[9px] text-center text-[.72rem] font-bold text-ct-ink">Transit<span class="sr-only"> (current step)</span></span></li>
    <li class="flex flex-1 flex-col"><span class="mx-[3px] h-[5px] rounded-full bg-ct-off"></span><span class="mt-[9px] text-center text-[.72rem] text-ct-light">Delivered<span class="sr-only"> (to do)</span></span></li>
  </ol>
</div>

<div class="rounded-[13px] border border-ct-off bg-white px-[18px] py-4 text-ct-ink">
  <div class="mb-3.5 flex items-baseline justify-between"><b class="text-[.9rem]">Dot connector</b><span class="text-[.77rem] text-ct-muted">Out for delivery</span></div>
  <div class="flex items-center gap-[7px] text-[.79rem] text-ct-muted">
    <ol class="flex flex-1 items-center gap-[7px]">
      <li class="flex flex-1 items-center gap-[7px]"><i class="size-[9px] shrink-0 rounded-full bg-ct-done" aria-hidden="true"></i><span class="h-0.5 min-w-3.5 flex-1 bg-ct-done" aria-hidden="true"></span><span class="sr-only">Placed (done)</span></li>
      <li class="flex flex-1 items-center gap-[7px]"><i class="size-[9px] shrink-0 rounded-full bg-ct-done" aria-hidden="true"></i><span class="h-0.5 min-w-3.5 flex-1 bg-ct-done" aria-hidden="true"></span><span class="sr-only">Packed (done)</span></li>
      <li class="flex flex-1 items-center gap-[7px]" aria-current="step"><i class="size-[9px] shrink-0 rounded-full bg-ct-now shadow-[0_0_0_3px_rgba(79,70,229,.18)]" aria-hidden="true"></i><span class="h-0.5 min-w-3.5 flex-1 bg-ct-off" aria-hidden="true"></span><span class="sr-only">In transit (current step)</span></li>
      <li class="flex items-center gap-[7px]"><i class="size-[9px] shrink-0 rounded-full bg-ct-off" aria-hidden="true"></i><span class="sr-only">Delivered (to do)</span></li>
    </ol>
    <span class="ml-2.5">Arrives Thu</span>
  </div>
</div>

<div class="rounded-[13px] border border-ct-off bg-white px-[18px] py-4 text-ct-ink">
  <div class="mb-3.5 flex items-baseline justify-between"><b class="text-[.9rem]">Pill row</b><span class="text-[.77rem] text-ct-muted">For a table cell</span></div>
  <ol class="inline-flex items-center rounded-full bg-[#f1f4fa] p-1">
    <li class="rounded-full bg-white px-3 py-1 text-[.75rem] font-bold text-ct-ink shadow-[0_1px_3px_rgba(23,32,58,.14)]">Draft<span class="sr-only"> (done)</span></li>
    <li class="rounded-full bg-white px-3 py-1 text-[.75rem] font-bold text-ct-ink shadow-[0_1px_3px_rgba(23,32,58,.14)]">Review<span class="sr-only"> (done)</span></li>
    <li class="rounded-full bg-white px-3 py-1 text-[.75rem] font-bold text-ct-ink shadow-[0_1px_3px_rgba(23,32,58,.14)]" aria-current="step">Approved<span class="sr-only"> (current step)</span></li>
    <li class="rounded-full px-3 py-1 text-[.75rem] font-bold text-ct-muted">Live<span class="sr-only"> (to do)</span></li>
  </ol>
</div>
CSS
@theme {
  --color-ct-done: #16a34a;
  --color-ct-now: #4f46e5;
  --color-ct-off: #e3e8f2;
  --color-ct-ink: #17203a;
  --color-ct-muted: #5f6a86;
  --color-ct-light: #646f8b;
}

About this set

Three small progress trackers sized to sit inside a card, a list row or a table cell rather than take over a page. The segmented bar shows four rounded segments, green for completed steps and a part-filled indigo segment for the current one, with step names underneath and a Step 3 of 4 counter. The dot connector packs the same four steps into one line of dots and joining rules, followed by a short status such as Arrives Thu. The pill row is the smallest: a grey capsule holding four words, with the steps reached so far raised on white pills. Use the bar on order or shipment cards, the dots where only one line is free, and the pills for content workflow states like Draft, Review, Approved and Live. Each tracker is an ordered list, and every step carries visually hidden text saying whether it is done, current or still to do, with aria-current=”step” on the current one, so the state never depends on colour. The bars, dots and lines are decoration. The Bootstrap version wraps each tracker in a .card, and the Tailwind version uses flex and sr-only utilities.

What’s included

  • Segmented bar, dot connector and pill row variants
  • Each tracker is an ordered list of steps
  • Done, current and to-do states in visually hidden text
  • aria-current="step" on the current step
  • Fits inside a card or a table cell

Accessibility

Each tracker is an ordered list whose items end with visually hidden state text, for example Transit (current step), and the current item has aria-current="step". Dots, segments and connecting lines are aria-hidden or empty decoration. The step labels and pill text were darkened to meet 4.5:1, and nothing animates.

Customise it

Change --ct-done, --ct-now and --ct-off on .ct for the step colours and --ct-muted or --ct-light for the secondary text (plain CSS and Bootstrap), or the --color-ct-* theme colours in Tailwind. The current segment's fill is the 60% stop in its gradient.