Progress Indicator

Indicates progress.

60% complete

html

<div class="lod-prg-stage" data-style="bar">
  <div class="lod-prg-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"><span style="width:60%; background:#A8E6C1;"></span></div>
  <svg class="lod-prg-circle" viewBox="0 0 60 60" width="60" height="60" role="progressbar" aria-valuenow="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#24143022" stroke-width="6"/><circle cx="30" cy="30" r="26" fill="none" stroke="#A8E6C1" stroke-width="6" stroke-dasharray="163.4" style="stroke-dashoffset:calc(163.4px - (163.4px * 60 / 100)); transform:rotate(-90deg); transform-origin:50% 50%;"/></svg>
  <div class="lod-prg-steps"><span class="lod-prg-step lod-prg-step--1" style="background:#A8E6C1;"></span><span class="lod-prg-step lod-prg-step--2" style="background:#A8E6C1;"></span><span class="lod-prg-step lod-prg-step--3"></span></div>
  <p class="lod-prg-caption">60% complete</p>
</div>
<style>
.lod-prg-stage { width: 100%; max-width: 320px; padding: 16px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; font: 13px system-ui, sans-serif; color: #241430aa; text-align: center; }
.lod-prg-bar, .lod-prg-circle, .lod-prg-steps { display: none; }
[data-style="bar"] .lod-prg-bar { display: block; height: 10px; background: #24143014; border-radius: 999px; overflow: hidden; }
.lod-prg-bar span { display: block; height: 100%; border-radius: 999px; }
[data-style="circular"] .lod-prg-circle { display: inline-block; }
[data-style="steps"] .lod-prg-steps { display: flex; gap: 6px; justify-content: center; }
.lod-prg-step { width: 40px; height: 8px; border-radius: 4px; background: #24143022; }
.lod-prg-caption { margin: 10px 0 0; }
</style>

tailwind

<div class="w-full max-w-[320px] p-4 bg-[#FAF7F2] border border-[#24143022] rounded-xl font-sans text-sm text-[#241430]/70 text-center" data-style="bar">
  <div role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" class="tw-prg-bar hidden h-2.5 bg-[#24143014] rounded-full overflow-hidden"><span class="block h-full rounded-full" style="width:60%; background:#A8E6C1;"></span></div>
  <svg class="tw-prg-circle hidden" viewBox="0 0 60 60" width="60" height="60" role="progressbar" aria-valuenow="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#24143022" stroke-width="6"/><circle cx="30" cy="30" r="26" fill="none" stroke="#A8E6C1" stroke-width="6" stroke-dasharray="163.4" style="stroke-dashoffset:calc(163.4px - (163.4px * 60 / 100)); transform:rotate(-90deg); transform-origin:50% 50%;"/></svg>
  <div class="tw-prg-steps hidden gap-1.5 justify-center"><span class="w-10 h-2 rounded-sm" style="background:#A8E6C1;"></span><span class="w-10 h-2 rounded-sm" style="background:#A8E6C1;"></span><span class="w-10 h-2 rounded-sm bg-[#24143022]"></span></div>
  <p class="mt-2.5">60% complete</p>
</div>
<style>
[data-style="bar"] .tw-prg-bar { display: block; }
[data-style="circular"] .tw-prg-circle { display: inline-block; }
[data-style="steps"] .tw-prg-steps { display: flex; }
</style>

react

export function ProgressIndicator({
  style = "bar",
  value = 60,
  accent = "#A8E6C1",
}) {
  return (
    <div style={{ width: "100%", maxWidth: 320, padding: 16, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, fontFamily: "system-ui, sans-serif", fontSize: 13, color: "#241430aa", textAlign: "center" }}>
      {style === "bar" && (
        <div role="progressbar" aria-valuenow={value} aria-valuemin={0} aria-valuemax={100} style={{ height: 10, background: "#24143014", borderRadius: 999, overflow: "hidden" }}>
          <span style={{ display: "block", height: "100%", width: `${value}%`, background: accent, borderRadius: 999 }} />
        </div>
      )}
      {style === "circular" && (
        <svg viewBox="0 0 60 60" width="60" height="60" role="progressbar" aria-valuenow={value}>
          <circle cx="30" cy="30" r="26" fill="none" stroke="#24143022" strokeWidth="6" />
          <circle cx="30" cy="30" r="26" fill="none" stroke={accent} strokeWidth="6" strokeDasharray="163.4" style={{ strokeDashoffset: `calc(163.4px - (163.4px * ${value} / 100))`, transform: "rotate(-90deg)", transformOrigin: "50% 50%" }} />
        </svg>
      )}
      {style === "steps" && (
        <div style={{ display: "flex", gap: 6, justifyContent: "center" }}>
          <span style={{ width: 40, height: 8, borderRadius: 4, background: accent }} />
          <span style={{ width: 40, height: 8, borderRadius: 4, background: accent }} />
          <span style={{ width: 40, height: 8, borderRadius: 4, background: "#24143022" }} />
        </div>
      )}
      <p style={{ margin: "10px 0 0" }}>{value}% complete</p>
    </div>
  );
}