Open demo

CSS code

HTML
<div class="pg"><span class="lbl">Radial progress rings</span>
<div class="pg-rings">
  <article class="pg-card">
    <div class="pg-ring" style="--p:72" role="progressbar" aria-labelledby="pg-r1" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72" aria-valuetext="72%, $360,000 of $500,000">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">72%</span></div>
    <div class="pg-ring-text"><h3 class="pg-title" id="pg-r1">Q4 sales target</h3><p class="pg-sub pg-num">$360,000 of $500,000</p>
      <span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </article>
  <article class="pg-card">
    <div class="pg-ring is-warn" style="--p:86" role="progressbar" aria-labelledby="pg-r2" aria-valuemin="0" aria-valuemax="100" aria-valuenow="86" aria-valuetext="86%, 43 GB of 50 GB">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">86%</span></div>
    <div class="pg-ring-text"><h3 class="pg-title" id="pg-r2">Storage used</h3><p class="pg-sub pg-num">43 GB of 50 GB</p>
      <span class="pg-status is-warn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>Near limit</span></div>
  </article>
  <article class="pg-card">
    <div class="pg-ring" style="--p:91" role="progressbar" aria-labelledby="pg-r3" aria-valuemin="0" aria-valuemax="100" aria-valuenow="91" aria-valuetext="91%, 1,183 of 1,300 accounts">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">91%</span></div>
    <div class="pg-ring-text"><h3 class="pg-title" id="pg-r3">Onboarding done</h3><p class="pg-sub pg-num">1,183 of 1,300 accounts</p>
      <span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </article>
</div></div>

<div class="pg"><span class="lbl">Target bars with a pace marker</span>
<article class="pg-card pg-targets">
  <div class="pg-targets-head"><div><h3 class="pg-title">October targets</h3><p class="pg-sub">Day 16 of 31 · updated 09:40</p></div>
    <p class="pg-key"><i aria-hidden="true"></i>Marker: where you should be today (52%)</p></div>
  <ul class="pg-list">
    <li><div class="pg-row-top"><b id="pg-t1">New MRR</b><span class="pg-num"><strong>$9,820</strong> of $15,000</span><span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="pg-bar" style="--p:65%;--pace:52%" role="progressbar" aria-labelledby="pg-t1" aria-valuemin="0" aria-valuemax="15000" aria-valuenow="9820" aria-valuetext="$9,820 of $15,000, 65%, ahead of pace"><i></i></div></li>
    <li><div class="pg-row-top"><b id="pg-t2">Enterprise demos booked</b><span class="pg-num"><strong>21</strong> of 40</span><span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On pace</span></div>
      <div class="pg-bar" style="--p:52.5%;--pace:52%" role="progressbar" aria-labelledby="pg-t2" aria-valuemin="0" aria-valuemax="40" aria-valuenow="21" aria-valuetext="21 of 40, 53%, on pace"><i></i></div></li>
    <li><div class="pg-row-top"><b id="pg-t3">Newsletter signups</b><span class="pg-num"><strong>380</strong> of 1,000</span><span class="pg-status is-bad"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>Behind pace</span></div>
      <div class="pg-bar" style="--p:38%;--pace:52%" role="progressbar" aria-labelledby="pg-t3" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="380" aria-valuetext="380 of 1,000, 38%, behind pace"><i></i></div></li>
    <li><div class="pg-row-top"><b id="pg-t4">Partner referrals</b><span class="pg-num"><strong>14</strong> of 25</span><span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="pg-bar" style="--p:56%;--pace:52%" role="progressbar" aria-labelledby="pg-t4" aria-valuemin="0" aria-valuemax="25" aria-valuenow="14" aria-valuetext="14 of 25, 56%, ahead of pace"><i></i></div></li>
  </ul>
</article></div>

<div class="pg"><span class="lbl">Goal with milestones</span>
<article class="pg-card pg-goal">
  <div class="pg-goal-top"><div><h3 class="pg-title" id="pg-goal">2026 signup goal</h3><p class="pg-big pg-num">8,412 <small>of 10,000 signups</small></p></div>
    <span class="pg-status is-good"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>494 ahead of plan</span></div>
  <div class="pg-meter"><progress max="10000" value="8412" aria-labelledby="pg-goal" aria-valuetext="8,412 of 10,000 signups, 84%">84%</progress><span class="pg-ticks" aria-hidden="true"></span></div>
  <ol class="pg-miles" aria-label="Milestones">
    <li class="is-done"><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>2,500</strong>Reached Mar 14</li>
    <li class="is-done"><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>5,000</strong>Reached Jul 2</li>
    <li class="is-done"><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>7,500</strong>Reached Sep 21</li>
    <li><strong>10,000</strong>1,588 to go</li>
  </ol>
</article></div>
CSS
/* Goal and progress widgets. Every bar or ring is a progressbar (ARIA role or native <progress>) with a name
   and a value text, and the same numbers are printed beside it. Status is a word plus an icon, not just a colour. */
.pg{--pg-ink:#0f172a;--pg-muted:#4b5768;--pg-line:#e2e8f0;--pg-track:#e2e8f0;--pg-fill:#2a78d6;--pg-warn:#b45309;--pg-warn-bg:#fef3c7;
  --pg-good:#15803d;--pg-good-bg:#dcfce7;--pg-bad:#b91c1c;--pg-bad-bg:#fee2e2;--pg-mark:#0f172a;color:var(--pg-ink)}
.pg-card{background:#fff;border:1px solid var(--pg-line);border-radius:16px;padding:20px;box-shadow:0 1px 2px rgba(15,23,42,.04),0 8px 24px rgba(15,23,42,.05);min-width:0}
.pg-title{font-size:1rem;font-weight:700}
.pg-sub{font-size:.8rem;color:var(--pg-muted)}
.pg-num{font-variant-numeric:tabular-nums}
.pg-status{display:inline-flex;align-items:center;gap:4px;padding:2px 8px 2px 6px;border-radius:999px;font-size:.74rem;font-weight:700;white-space:nowrap}
.pg-status svg{width:13px;height:13px;flex:none}
.pg-status.is-good{color:var(--pg-good);background:var(--pg-good-bg)}
.pg-status.is-warn{color:var(--pg-warn);background:var(--pg-warn-bg)}
.pg-status.is-bad{color:var(--pg-bad);background:var(--pg-bad-bg)}
/* radial rings */
.pg-rings{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
.pg-rings .pg-card{display:flex;align-items:center;gap:16px}
.pg-ring{position:relative;flex:none;width:96px;height:96px}
.pg-ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.pg-ring circle{fill:none;stroke-width:10}
.pg-ring .trk{stroke:var(--pg-track)}
.pg-ring .bar{stroke:var(--pg-fill);stroke-linecap:round;stroke-dasharray:var(--p) 100;transition:stroke-dasharray .6s ease}
.pg-ring.is-warn .bar{stroke:#d97706}
.pg-ring span{position:absolute;inset:0;display:grid;place-items:center;font-size:1.15rem;font-weight:750;font-variant-numeric:tabular-nums}
.pg-ring-text{display:flex;flex-direction:column;gap:4px;align-items:flex-start;min-width:0}
/* target bars */
.pg-targets{display:flex;flex-direction:column;gap:18px}
.pg-targets-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap}
.pg-list{list-style:none;display:flex;flex-direction:column;gap:18px}
.pg-row-top{display:flex;justify-content:space-between;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:8px;font-size:.88rem}
.pg-row-top b{font-weight:600;margin-right:auto}
.pg-row-top .pg-num{color:var(--pg-muted)}
.pg-row-top .pg-num strong{color:var(--pg-ink)}
.pg-bar{position:relative;height:10px;border-radius:999px;background:var(--pg-track)}
.pg-bar i{position:absolute;inset:0 auto 0 0;width:var(--p);border-radius:inherit;background:var(--pg-fill);transition:width .6s ease}
.pg-bar::after{content:"";position:absolute;left:var(--pace);top:-4px;bottom:-4px;width:2px;border-radius:2px;background:var(--pg-mark)}
.pg-key{display:flex;align-items:center;gap:8px;font-size:.78rem;color:var(--pg-muted)}
.pg-key i{width:2px;height:14px;background:var(--pg-mark);border-radius:2px}
/* goal with milestones (native <progress>) */
.pg-goal{display:flex;flex-direction:column;gap:14px}
.pg-goal-top{display:flex;justify-content:space-between;align-items:flex-end;gap:12px;flex-wrap:wrap}
.pg-big{font-size:2.2rem;font-weight:750;letter-spacing:-.02em;line-height:1.1}
.pg-big small{font-size:1rem;font-weight:600;color:var(--pg-muted);letter-spacing:0}
.pg-meter{position:relative}
.pg-meter progress{-webkit-appearance:none;appearance:none;display:block;width:100%;height:14px;border:0;border-radius:999px;background:var(--pg-track);overflow:hidden;color:var(--pg-fill)}
.pg-meter progress::-webkit-progress-bar{background:var(--pg-track);border-radius:999px}
.pg-meter progress::-webkit-progress-value{background:var(--pg-fill);border-radius:999px}
.pg-meter progress::-moz-progress-bar{background:var(--pg-fill);border-radius:999px}
.pg-ticks{position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,transparent calc(25% - 1px),#fff calc(25% - 1px) calc(25% + 1px),transparent 0 calc(50% - 1px),#fff 0 calc(50% + 1px),transparent 0 calc(75% - 1px),#fff 0 calc(75% + 1px),transparent 0)}
.pg-miles{list-style:none;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
.pg-miles li{display:flex;flex-direction:column;align-items:flex-end;text-align:right;gap:2px;font-size:.8rem;color:var(--pg-muted);padding-top:10px;border-top:2px solid var(--pg-line)}
.pg-miles li.is-done{border-top-color:var(--pg-fill)}
.pg-miles strong{display:flex;align-items:center;gap:5px;font-size:.95rem;color:var(--pg-ink);font-variant-numeric:tabular-nums}
.pg-miles svg{width:15px;height:15px;color:var(--pg-good)}
.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}
@media (max-width:560px){.pg-miles{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (prefers-reduced-motion:reduce){.pg-ring .bar,.pg-bar i{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="pg"><span class="lbl">Radial progress rings</span>
<div class="row row-cols-1 row-cols-md-3 g-3">
  <div class="col"><article class="card h-100"><div class="card-body d-flex align-items-center gap-3">
    <div class="pg-ring" style="--p:72" role="progressbar" aria-labelledby="pg-r1" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72" aria-valuetext="72%, $360,000 of $500,000">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">72%</span></div>
    <div class="d-flex flex-column align-items-start gap-1 min-w-0"><h3 class="pg-title mb-0" id="pg-r1">Q4 sales target</h3><p class="pg-sub pg-num mb-0">$360,000 of $500,000</p>
      <span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </div></article></div>
  <div class="col"><article class="card h-100"><div class="card-body d-flex align-items-center gap-3">
    <div class="pg-ring is-warn" style="--p:86" role="progressbar" aria-labelledby="pg-r2" aria-valuemin="0" aria-valuemax="100" aria-valuenow="86" aria-valuetext="86%, 43 GB of 50 GB">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">86%</span></div>
    <div class="d-flex flex-column align-items-start gap-1 min-w-0"><h3 class="pg-title mb-0" id="pg-r2">Storage used</h3><p class="pg-sub pg-num mb-0">43 GB of 50 GB</p>
      <span class="badge rounded-pill bg-warning-subtle text-warning-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>Near limit</span></div>
  </div></article></div>
  <div class="col"><article class="card h-100"><div class="card-body d-flex align-items-center gap-3">
    <div class="pg-ring" style="--p:91" role="progressbar" aria-labelledby="pg-r3" aria-valuemin="0" aria-valuemax="100" aria-valuenow="91" aria-valuetext="91%, 1,183 of 1,300 accounts">
      <svg viewBox="0 0 100 100" aria-hidden="true"><circle class="trk" cx="50" cy="50" r="42"/><circle class="bar" cx="50" cy="50" r="42" pathLength="100"/></svg><span aria-hidden="true">91%</span></div>
    <div class="d-flex flex-column align-items-start gap-1 min-w-0"><h3 class="pg-title mb-0" id="pg-r3">Onboarding done</h3><p class="pg-sub pg-num mb-0">1,183 of 1,300 accounts</p>
      <span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </div></article></div>
</div></div>

<div class="pg"><span class="lbl">Target bars with a pace marker</span>
<article class="card"><div class="card-body d-flex flex-column gap-3">
  <div class="d-flex justify-content-between align-items-start flex-wrap gap-3"><div><h3 class="pg-title mb-0">October targets</h3><p class="pg-sub mb-0">Day 16 of 31 · updated 09:40</p></div>
    <p class="pg-key d-flex align-items-center gap-2 mb-0"><i aria-hidden="true"></i>Marker: where you should be today (52%)</p></div>
  <ul class="list-unstyled d-flex flex-column gap-3 mb-0">
    <li><div class="d-flex justify-content-between align-items-baseline flex-wrap gap-2 mb-2 pg-row-top"><b id="pg-t1">New MRR</b><span class="pg-num text-body-secondary"><strong class="text-body">$9,820</strong> of $15,000</span><span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="pg-pace" style="--pace:52%"><div class="progress" role="progressbar" aria-labelledby="pg-t1" aria-valuemin="0" aria-valuemax="15000" aria-valuenow="9820" aria-valuetext="$9,820 of $15,000, 65%, ahead of pace"><div class="progress-bar" style="width:65%"></div></div></div></li>
    <li><div class="d-flex justify-content-between align-items-baseline flex-wrap gap-2 mb-2 pg-row-top"><b id="pg-t2">Enterprise demos booked</b><span class="pg-num text-body-secondary"><strong class="text-body">21</strong> of 40</span><span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On pace</span></div>
      <div class="pg-pace" style="--pace:52%"><div class="progress" role="progressbar" aria-labelledby="pg-t2" aria-valuemin="0" aria-valuemax="40" aria-valuenow="21" aria-valuetext="21 of 40, 53%, on pace"><div class="progress-bar" style="width:52.5%"></div></div></div></li>
    <li><div class="d-flex justify-content-between align-items-baseline flex-wrap gap-2 mb-2 pg-row-top"><b id="pg-t3">Newsletter signups</b><span class="pg-num text-body-secondary"><strong class="text-body">380</strong> of 1,000</span><span class="badge rounded-pill bg-danger-subtle text-danger-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>Behind pace</span></div>
      <div class="pg-pace" style="--pace:52%"><div class="progress" role="progressbar" aria-labelledby="pg-t3" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="380" aria-valuetext="380 of 1,000, 38%, behind pace"><div class="progress-bar" style="width:38%"></div></div></div></li>
    <li><div class="d-flex justify-content-between align-items-baseline flex-wrap gap-2 mb-2 pg-row-top"><b id="pg-t4">Partner referrals</b><span class="pg-num text-body-secondary"><strong class="text-body">14</strong> of 25</span><span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="pg-pace" style="--pace:52%"><div class="progress" role="progressbar" aria-labelledby="pg-t4" aria-valuemin="0" aria-valuemax="25" aria-valuenow="14" aria-valuetext="14 of 25, 56%, ahead of pace"><div class="progress-bar" style="width:56%"></div></div></div></li>
  </ul>
</div></article></div>

<div class="pg"><span class="lbl">Goal with milestones</span>
<article class="card pg-goal"><div class="card-body d-flex flex-column gap-3">
  <div class="d-flex justify-content-between align-items-end flex-wrap gap-3"><div><h3 class="pg-title mb-0" id="pg-goal">2026 signup goal</h3><p class="pg-big pg-num mb-0">8,412 <small>of 10,000 signups</small></p></div>
    <span class="badge rounded-pill bg-success-subtle text-success-emphasis"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>494 ahead of plan</span></div>
  <div class="progress" role="progressbar" aria-labelledby="pg-goal" aria-valuemin="0" aria-valuemax="10000" aria-valuenow="8412" aria-valuetext="8,412 of 10,000 signups, 84%"><div class="progress-bar" style="width:84.12%"></div><span class="pg-ticks" aria-hidden="true"></span></div>
  <ol class="pg-miles row row-cols-2 row-cols-sm-4 g-2 list-unstyled mb-0" aria-label="Milestones">
    <li class="col is-done"><div><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>2,500</strong>Reached Mar 14</div></li>
    <li class="col is-done"><div><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>5,000</strong>Reached Jul 2</div></li>
    <li class="col is-done"><div><strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>7,500</strong>Reached Sep 21</div></li>
    <li class="col"><div><strong>10,000</strong>1,588 to go</div></li>
  </ol>
</div></article></div>
CSS
/* Bootstrap .card, .progress (role="progressbar") and .badge; the rings are a small SVG. Colours via Bootstrap variables on .pg. */
.pg{--bs-body-color:#0f172a;--bs-secondary-color:#4b5768;--bs-card-border-color:#e2e8f0;
  --bs-success-text-emphasis:#15803d;--bs-success-bg-subtle:#dcfce7;--bs-danger-text-emphasis:#b91c1c;--bs-danger-bg-subtle:#fee2e2;--bs-warning-text-emphasis:#b45309;--bs-warning-bg-subtle:#fef3c7;
  --pg-mark:#0f172a;color:var(--bs-body-color)}
.pg .card{--bs-card-border-color:#e2e8f0;--bs-card-border-radius:16px;--bs-card-spacer-x:20px;--bs-card-spacer-y:20px;box-shadow:0 1px 2px rgba(15,23,42,.04),0 8px 24px rgba(15,23,42,.05)}
.pg .progress{--bs-progress-bg:#e2e8f0;--bs-progress-bar-bg:#2a78d6;--bs-progress-height:10px;--bs-progress-border-radius:999px}
.pg .progress-bar{border-radius:999px}
.pg-title{font-size:1rem;font-weight:700}
.pg-sub{font-size:.8rem;color:var(--bs-secondary-color)}
.pg-num{font-variant-numeric:tabular-nums}
.pg .badge{display:inline-flex;align-items:center;gap:4px;padding:3px 8px 3px 6px;font-size:.74rem;font-weight:700}
.pg .badge svg{width:13px;height:13px;flex:none}
.min-w-0{min-width:0}
.pg-ring{position:relative;flex:none;width:96px;height:96px}
.pg-ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.pg-ring circle{fill:none;stroke-width:10}
.pg-ring .trk{stroke:#e2e8f0}
.pg-ring .bar{stroke:#2a78d6;stroke-linecap:round;stroke-dasharray:var(--p) 100;transition:stroke-dasharray .6s ease}
.pg-ring.is-warn .bar{stroke:#d97706}
.pg-ring span{position:absolute;inset:0;display:grid;place-items:center;font-size:1.15rem;font-weight:750;font-variant-numeric:tabular-nums}
.pg-row-top{font-size:.88rem}
.pg-row-top b{font-weight:600;margin-right:auto}
.pg-pace{position:relative}
.pg-pace::after{content:"";position:absolute;left:var(--pace);top:-4px;bottom:-4px;width:2px;border-radius:2px;background:var(--pg-mark)}
.pg-key{font-size:.78rem;color:var(--bs-secondary-color)}
.pg-key i{width:2px;height:14px;background:var(--pg-mark);border-radius:2px}
.pg-big{font-size:2.2rem;font-weight:750;letter-spacing:-.02em;line-height:1.1}
.pg-big small{font-size:1rem;font-weight:600;color:var(--bs-secondary-color);letter-spacing:0}
.pg .pg-goal .progress{--bs-progress-height:14px;position:relative}
.pg-ticks{position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,transparent calc(25% - 1px),#fff calc(25% - 1px) calc(25% + 1px),transparent 0 calc(50% - 1px),#fff 0 calc(50% + 1px),transparent 0 calc(75% - 1px),#fff 0 calc(75% + 1px),transparent 0)}
.pg-miles li{font-size:.8rem;color:var(--bs-secondary-color);text-align:right}
.pg-miles li>div{padding-top:10px;border-top:2px solid #e2e8f0}
.pg-miles li.is-done>div{border-top-color:#2a78d6}
.pg-miles strong{display:flex;justify-content:flex-end;align-items:center;gap:5px;font-size:.95rem;color:var(--bs-body-color);font-variant-numeric:tabular-nums}
.pg-miles svg{width:15px;height:15px;color:#15803d}
@media (prefers-reduced-motion:reduce){.pg-ring .bar,.pg .progress-bar{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#4b5768] uppercase">Radial progress rings</span>
<div class="grid grid-cols-[repeat(auto-fit,minmax(220px,1fr))] gap-4">
  <article class="flex min-w-0 items-center gap-4 rounded-2xl border border-[#e2e8f0] bg-white p-5 shadow-[0_1px_2px_rgba(15,23,42,.04),0_8px_24px_rgba(15,23,42,.05)]">
    <div class="relative size-24 flex-none" role="progressbar" aria-labelledby="pg-r1" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72" aria-valuetext="72%, $360,000 of $500,000">
      <svg class="size-full -rotate-90" viewBox="0 0 100 100" aria-hidden="true"><circle class="fill-none stroke-[#e2e8f0] [stroke-width:10]" cx="50" cy="50" r="42"/><circle class="fill-none stroke-[#2a78d6] [stroke-width:10] [stroke-linecap:round] [stroke-dasharray:72_100] transition-[stroke-dasharray] duration-600 ease-in-out motion-reduce:transition-none" cx="50" cy="50" r="42" pathLength="100"/></svg><span class="absolute inset-0 grid place-items-center text-[1.15rem] font-[750] tabular-nums" aria-hidden="true">72%</span></div>
    <div class="flex min-w-0 flex-col items-start gap-1"><h3 class="text-base font-bold" id="pg-r1">Q4 sales target</h3><p class="text-[.8rem] text-[#4b5768] tabular-nums">$360,000 of $500,000</p>
      <span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </article>
  <article class="flex min-w-0 items-center gap-4 rounded-2xl border border-[#e2e8f0] bg-white p-5 shadow-[0_1px_2px_rgba(15,23,42,.04),0_8px_24px_rgba(15,23,42,.05)]">
    <div class="relative size-24 flex-none" role="progressbar" aria-labelledby="pg-r2" aria-valuemin="0" aria-valuemax="100" aria-valuenow="86" aria-valuetext="86%, 43 GB of 50 GB">
      <svg class="size-full -rotate-90" viewBox="0 0 100 100" aria-hidden="true"><circle class="fill-none stroke-[#e2e8f0] [stroke-width:10]" cx="50" cy="50" r="42"/><circle class="fill-none stroke-[#d97706] [stroke-width:10] [stroke-linecap:round] [stroke-dasharray:86_100] transition-[stroke-dasharray] duration-600 ease-in-out motion-reduce:transition-none" cx="50" cy="50" r="42" pathLength="100"/></svg><span class="absolute inset-0 grid place-items-center text-[1.15rem] font-[750] tabular-nums" aria-hidden="true">86%</span></div>
    <div class="flex min-w-0 flex-col items-start gap-1"><h3 class="text-base font-bold" id="pg-r2">Storage used</h3><p class="text-[.8rem] text-[#4b5768] tabular-nums">43 GB of 50 GB</p>
      <span class="inline-flex items-center gap-1 rounded-full bg-[#fef3c7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#b45309]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>Near limit</span></div>
  </article>
  <article class="flex min-w-0 items-center gap-4 rounded-2xl border border-[#e2e8f0] bg-white p-5 shadow-[0_1px_2px_rgba(15,23,42,.04),0_8px_24px_rgba(15,23,42,.05)]">
    <div class="relative size-24 flex-none" role="progressbar" aria-labelledby="pg-r3" aria-valuemin="0" aria-valuemax="100" aria-valuenow="91" aria-valuetext="91%, 1,183 of 1,300 accounts">
      <svg class="size-full -rotate-90" viewBox="0 0 100 100" aria-hidden="true"><circle class="fill-none stroke-[#e2e8f0] [stroke-width:10]" cx="50" cy="50" r="42"/><circle class="fill-none stroke-[#2a78d6] [stroke-width:10] [stroke-linecap:round] [stroke-dasharray:91_100] transition-[stroke-dasharray] duration-600 ease-in-out motion-reduce:transition-none" cx="50" cy="50" r="42" pathLength="100"/></svg><span class="absolute inset-0 grid place-items-center text-[1.15rem] font-[750] tabular-nums" aria-hidden="true">91%</span></div>
    <div class="flex min-w-0 flex-col items-start gap-1"><h3 class="text-base font-bold" id="pg-r3">Onboarding done</h3><p class="text-[.8rem] text-[#4b5768] tabular-nums">1,183 of 1,300 accounts</p>
      <span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On track</span></div>
  </article>
</div></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#4b5768] uppercase">Target bars with a pace marker</span>
<article class="flex flex-col gap-[18px] rounded-2xl border border-[#e2e8f0] bg-white p-5 shadow-[0_1px_2px_rgba(15,23,42,.04),0_8px_24px_rgba(15,23,42,.05)]">
  <div class="flex flex-wrap items-start justify-between gap-3"><div><h3 class="text-base font-bold">October targets</h3><p class="text-[.8rem] text-[#4b5768]">Day 16 of 31 · updated 09:40</p></div>
    <p class="flex items-center gap-2 text-[.78rem] text-[#4b5768]"><i class="h-3.5 w-0.5 rounded-sm bg-[#0f172a]" aria-hidden="true"></i>Marker: where you should be today (52%)</p></div>
  <ul class="flex flex-col gap-[18px]">
    <li><div class="mb-2 flex flex-wrap items-baseline justify-between gap-2.5 text-[.88rem]"><b class="mr-auto font-semibold" id="pg-t1">New MRR</b><span class="text-[#4b5768] tabular-nums"><strong class="text-[#0f172a]">$9,820</strong> of $15,000</span><span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="relative h-2.5 rounded-full bg-[#e2e8f0] after:absolute after:-inset-y-1 after:left-[52%] after:w-0.5 after:rounded-sm after:bg-[#0f172a]" role="progressbar" aria-labelledby="pg-t1" aria-valuemin="0" aria-valuemax="15000" aria-valuenow="9820" aria-valuetext="$9,820 of $15,000, 65%, ahead of pace"><i class="absolute inset-y-0 left-0 w-[65%] rounded-full bg-[#2a78d6] transition-[width] duration-600 motion-reduce:transition-none"></i></div></li>
    <li><div class="mb-2 flex flex-wrap items-baseline justify-between gap-2.5 text-[.88rem]"><b class="mr-auto font-semibold" id="pg-t2">Enterprise demos booked</b><span class="text-[#4b5768] tabular-nums"><strong class="text-[#0f172a]">21</strong> of 40</span><span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>On pace</span></div>
      <div class="relative h-2.5 rounded-full bg-[#e2e8f0] after:absolute after:-inset-y-1 after:left-[52%] after:w-0.5 after:rounded-sm after:bg-[#0f172a]" role="progressbar" aria-labelledby="pg-t2" aria-valuemin="0" aria-valuemax="40" aria-valuenow="21" aria-valuetext="21 of 40, 53%, on pace"><i class="absolute inset-y-0 left-0 w-[52.5%] rounded-full bg-[#2a78d6] transition-[width] duration-600 motion-reduce:transition-none"></i></div></li>
    <li><div class="mb-2 flex flex-wrap items-baseline justify-between gap-2.5 text-[.88rem]"><b class="mr-auto font-semibold" id="pg-t3">Newsletter signups</b><span class="text-[#4b5768] tabular-nums"><strong class="text-[#0f172a]">380</strong> of 1,000</span><span class="inline-flex items-center gap-1 rounded-full bg-[#fee2e2] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#b91c1c]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>Behind pace</span></div>
      <div class="relative h-2.5 rounded-full bg-[#e2e8f0] after:absolute after:-inset-y-1 after:left-[52%] after:w-0.5 after:rounded-sm after:bg-[#0f172a]" role="progressbar" aria-labelledby="pg-t3" aria-valuemin="0" aria-valuemax="1000" aria-valuenow="380" aria-valuetext="380 of 1,000, 38%, behind pace"><i class="absolute inset-y-0 left-0 w-[38%] rounded-full bg-[#2a78d6] transition-[width] duration-600 motion-reduce:transition-none"></i></div></li>
    <li><div class="mb-2 flex flex-wrap items-baseline justify-between gap-2.5 text-[.88rem]"><b class="mr-auto font-semibold" id="pg-t4">Partner referrals</b><span class="text-[#4b5768] tabular-nums"><strong class="text-[#0f172a]">14</strong> of 25</span><span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>Ahead of pace</span></div>
      <div class="relative h-2.5 rounded-full bg-[#e2e8f0] after:absolute after:-inset-y-1 after:left-[52%] after:w-0.5 after:rounded-sm after:bg-[#0f172a]" role="progressbar" aria-labelledby="pg-t4" aria-valuemin="0" aria-valuemax="25" aria-valuenow="14" aria-valuetext="14 of 25, 56%, ahead of pace"><i class="absolute inset-y-0 left-0 w-[56%] rounded-full bg-[#2a78d6] transition-[width] duration-600 motion-reduce:transition-none"></i></div></li>
  </ul>
</article></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#4b5768] uppercase">Goal with milestones</span>
<article class="flex flex-col gap-3.5 rounded-2xl border border-[#e2e8f0] bg-white p-5 shadow-[0_1px_2px_rgba(15,23,42,.04),0_8px_24px_rgba(15,23,42,.05)]">
  <div class="flex flex-wrap items-end justify-between gap-3"><div><h3 class="text-base font-bold" id="pg-goal">2026 signup goal</h3><p class="text-[2.2rem] leading-[1.1] font-[750] tracking-[-.02em] tabular-nums">8,412 <small class="text-base font-semibold tracking-normal text-[#4b5768]">of 10,000 signups</small></p></div>
    <span class="inline-flex items-center gap-1 rounded-full bg-[#dcfce7] py-0.5 pr-2 pl-1.5 text-[.74rem] font-bold whitespace-nowrap text-[#15803d]"><svg class="size-[13px] flex-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>494 ahead of plan</span></div>
  <div class="relative"><progress class="block h-3.5 w-full appearance-none overflow-hidden rounded-full border-0 bg-[#e2e8f0] [&::-moz-progress-bar]:rounded-full [&::-moz-progress-bar]:bg-[#2a78d6] [&::-webkit-progress-bar]:bg-[#e2e8f0] [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:bg-[#2a78d6]" max="10000" value="8412" aria-labelledby="pg-goal" aria-valuetext="8,412 of 10,000 signups, 84%">84%</progress><span class="pointer-events-none absolute inset-0 bg-[linear-gradient(90deg,transparent_calc(25%-1px),#fff_calc(25%-1px)_calc(25%+1px),transparent_0_calc(50%-1px),#fff_0_calc(50%+1px),transparent_0_calc(75%-1px),#fff_0_calc(75%+1px),transparent_0)]" aria-hidden="true"></span></div>
  <ol class="grid grid-cols-2 gap-2.5 sm:grid-cols-4" aria-label="Milestones">
    <li class="flex flex-col items-end gap-0.5 border-t-2 pt-2.5 text-right text-[.8rem] text-[#4b5768] border-[#2a78d6]"><strong class="flex items-center gap-[5px] text-[.95rem] text-[#0f172a] tabular-nums"><svg class="size-[15px] text-[#15803d]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>2,500</strong>Reached Mar 14</li>
    <li class="flex flex-col items-end gap-0.5 border-t-2 pt-2.5 text-right text-[.8rem] text-[#4b5768] border-[#2a78d6]"><strong class="flex items-center gap-[5px] text-[.95rem] text-[#0f172a] tabular-nums"><svg class="size-[15px] text-[#15803d]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>5,000</strong>Reached Jul 2</li>
    <li class="flex flex-col items-end gap-0.5 border-t-2 pt-2.5 text-right text-[.8rem] text-[#4b5768] border-[#2a78d6]"><strong class="flex items-center gap-[5px] text-[.95rem] text-[#0f172a] tabular-nums"><svg class="size-[15px] text-[#15803d]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>7,500</strong>Reached Sep 21</li>
    <li class="flex flex-col items-end gap-0.5 border-t-2 pt-2.5 text-right text-[.8rem] text-[#4b5768] border-[#e2e8f0]"><strong class="flex items-center gap-[5px] text-[.95rem] text-[#0f172a] tabular-nums">10,000</strong>1,588 to go</li>
  </ol>
</article></div>

About this set

Widgets for tracking a number against a target. Radial progress rings shows three cards with an SVG ring each: a quarterly sales target, storage used and onboarding completion, with the percentage in the middle, the raw figures underneath and a status badge such as On track or Near limit. Target bars with a pace marker lists October targets as horizontal bars, each with a thin marker for where the team should be on day 16 of 31, so ahead of pace and behind pace are visible at a glance and also written in a badge. Goal with milestones tracks an annual signup goal with a native progress element divided into quarters, a large current count and a milestone row showing which steps were reached and when. Use rings for a few headline goals, bars for a list of targets, and the milestone card for one long-running goal. The rings use pathLength so the percentage maps straight onto stroke-dasharray, and every ring and bar is a named progressbar with a value text. No JavaScript.

What’s included

  • SVG progress rings driven by a single percentage
  • Target bars with an expected-pace marker
  • Native progress element with milestone ticks
  • Status written as a word with an icon, never colour alone
  • Every bar and ring is a labelled progressbar with a value text
  • Bootstrap version uses .progress and .badge

Accessibility

Rings and target bars use role="progressbar" with aria-valuemin, aria-valuemax, aria-valuenow and an aria-valuetext such as "$9,820 of $15,000, 65%, ahead of pace", named by their visible heading. The goal uses a native progress element. Status badges pair an icon with a word, and fill transitions are switched off under prefers-reduced-motion.

Customise it

Change --pg-fill, --pg-track and --pg-mark on .pg for the bar, track and pace marker, and set --p (and --pace) on each ring or bar. In Bootstrap set --bs-progress-bar-bg on .progress; in Tailwind change the bg- and stroke- colour classes.