Skip to content
← Progress Ring
Edit Progress Ring
Name
Also known as (comma separated)
Brief definition
Circular progress indicator.
Notes
Tier
Core
Useful
Reference
Deleted
Controls schema (JSON array)
[ { "id": "label", "type": "text", "label": "Label", "default": "Storage used" }, { "id": "value", "type": "number", "label": "Value (%)", "default": 68, "min": 0, "max": 100, "step": 1 }, { "id": "color", "type": "color", "label": "Colour", "default": "#BFD9F2", "presets": [ "#BFD9F2", "#A8E6C1", "#E8A020", "#F5C2E0", "#D9C8F0", "#241430" ] }, { "id": "indeterminate", "type": "toggle", "label": "Indeterminate", "default": false } ]
Templates (JSON object keyed by format)
{ "html": "<div class=\"ring{{#if indeterminate}} ring--indeterminate{{/if}}\" role=\"progressbar\" aria-label=\"{{label}}\" aria-valuemin=\"0\" aria-valuemax=\"100\" {{#unless indeterminate}}aria-valuenow=\"{{value}}\"{{/unless}} style=\"--pct:{{value}};--c:{{color}};\">\n <svg width=\"88\" height=\"88\" viewBox=\"0 0 88 88\" aria-hidden=\"true\">\n <circle cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke=\"#24143018\" stroke-width=\"8\"></circle>\n <circle class=\"ring__arc\" cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke=\"{{color}}\" stroke-width=\"8\" stroke-linecap=\"round\"></circle>\n </svg>\n <div class=\"ring__center\">\n {{#unless indeterminate}}<span class=\"ring__value\">{{value}}%</span>{{/unless}}\n <span class=\"ring__label\">{{label}}</span>\n </div>\n</div>\n<style>\n.ring { position: relative; width: 88px; height: 88px; font: 11px system-ui, sans-serif; color: #241430; }\n.ring__arc { stroke-dasharray: 238.76; stroke-dashoffset: calc(238.76 - (238.76 * var(--pct) / 100)); transform: rotate(-90deg); transform-origin: 50% 50%; }\n.ring--indeterminate .ring__arc { stroke-dasharray: 60 178.76; }\n@keyframes ring-spin { to { transform: rotate(270deg); } }\n@media (prefers-reduced-motion: no-preference) {\n .ring__arc { transition: stroke-dashoffset .2s ease; }\n .ring--indeterminate .ring__arc { animation: ring-spin .2s linear infinite; }\n}\n.ring__center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 2px; }\n.ring__value { font-weight: 700; font-size: 15px; }\n.ring__label { opacity: .7; max-width: 70px; }\n</style>", "tailwind": "<div role=\"progressbar\" aria-label=\"{{label}}\" aria-valuemin=\"0\" aria-valuemax=\"100\" {{#unless indeterminate}}aria-valuenow=\"{{value}}\"{{/unless}} class=\"ring-tw{{#if indeterminate}} ring-tw--indeterminate{{/if}} relative w-[88px] h-[88px] font-sans text-[11px] text-[#241430]\" style=\"--pct:{{value}};--c:{{color}};\">\n <svg width=\"88\" height=\"88\" viewBox=\"0 0 88 88\" aria-hidden=\"true\">\n <circle cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke=\"#24143018\" stroke-width=\"8\"></circle>\n <circle class=\"ring-tw__arc\" cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke=\"{{color}}\" stroke-width=\"8\" stroke-linecap=\"round\"></circle>\n </svg>\n <div class=\"absolute inset-0 flex flex-col items-center justify-center text-center gap-0.5\">\n {{#unless indeterminate}}<span class=\"font-bold text-[15px]\">{{value}}%</span>{{/unless}}\n <span class=\"opacity-70 max-w-[70px]\">{{label}}</span>\n </div>\n</div>\n<style>\n.ring-tw__arc { stroke-dasharray: 238.76; stroke-dashoffset: calc(238.76 - (238.76 * var(--pct) / 100)); transform: rotate(-90deg); transform-origin: 50% 50%; }\n.ring-tw--indeterminate .ring-tw__arc { stroke-dasharray: 60 178.76; }\n@keyframes ring-tw-spin { to { transform: rotate(270deg); } }\n@media (prefers-reduced-motion: no-preference) {\n .ring-tw__arc { transition: stroke-dashoffset .2s ease; }\n .ring-tw--indeterminate .ring-tw__arc { animation: ring-tw-spin .2s linear infinite; }\n}\n</style>", "react": "export function ProgressRing({\n label = \"{{label}}\",\n value = {{value}},\n color = \"{{color}}\",\n indeterminate = {{indeterminate}},\n}) {\n const circumference = 238.76;\n const offset = circumference - (circumference * value) / 100;\n return (\n <div role=\"progressbar\" aria-label={label} aria-valuemin={0} aria-valuemax={100}\n aria-valuenow={indeterminate ? undefined : value}\n style={{ position: \"relative\", width: 88, height: 88, font: \"11px system-ui, sans-serif\", color: \"#241430\" }}>\n <svg width=\"88\" height=\"88\" viewBox=\"0 0 88 88\" aria-hidden=\"true\">\n <circle cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke=\"#24143018\" strokeWidth=\"8\" />\n <circle cx=\"44\" cy=\"44\" r=\"38\" fill=\"none\" stroke={color} strokeWidth=\"8\" strokeLinecap=\"round\"\n className={indeterminate ? \"pr-circle pr-circle--indeterminate\" : \"pr-circle\"}\n style={{ strokeDasharray: indeterminate ? \"60 178.76\" : circumference,\n strokeDashoffset: indeterminate ? 0 : offset, transform: \"rotate(-90deg)\", transformOrigin: \"50% 50%\" }} />\n </svg>\n <div style={{ position: \"absolute\", inset: 0, display: \"flex\", flexDirection: \"column\", alignItems: \"center\",\n justifyContent: \"center\", textAlign: \"center\", gap: 2 }}>\n {!indeterminate && <span style={{ fontWeight: 700, fontSize: 15 }}>{value}%</span>}\n <span style={{ opacity: 0.7, maxWidth: 70 }}>{label}</span>\n </div>\n <style>{`\n @media (prefers-reduced-motion: no-preference) {\n .pr-circle { transition: stroke-dashoffset .2s ease; }\n .pr-circle--indeterminate { animation: ring-react-spin 1s linear infinite; }\n @keyframes ring-react-spin { to { transform: rotate(270deg); } }\n }\n `}</style>\n </div>\n );\n}" }
Save
History