Skip to content
← Donut Chart
Edit Donut Chart
Name
Also known as (comma separated)
Brief definition
Pie chart with centre removed.
Notes
Tier
Core
Useful
Reference
Deleted
Controls schema (JSON array)
[ { "id": "highlightSegment", "type": "select", "label": "Highlight segment", "default": "first", "options": [ "first", "second", "third" ] }, { "id": "thickness", "type": "number", "label": "Ring thickness", "default": 18, "min": 8, "max": 30, "step": 1 }, { "id": "accent", "type": "color", "label": "Segment A colour", "default": "#A8E6C1", "presets": [ "#A8E6C1", "#F5C2E0", "#BFD9F2", "#D9C8F0", "#E8A020", "#241430" ] }, { "id": "showCenterLabel", "type": "toggle", "label": "Show centre label", "default": true } ]
Templates (JSON object keyed by format)
{ "html": "<div class=\"donut donut--{{highlightSegment}}\" style=\"--t:{{thickness}};--accent:{{accent}};\">\n <svg class=\"donut__ring\" width=\"140\" height=\"140\" viewBox=\"0 0 120 120\" aria-hidden=\"true\">\n <g transform=\"rotate(-90 60 60)\">\n <circle class=\"donut__seg donut__seg--1\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"120.64 130.69\" stroke-dashoffset=\"0\" />\n <circle class=\"donut__seg donut__seg--2\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"#D9C8F0\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"80.43 170.9\" stroke-dashoffset=\"-120.64\" />\n <circle class=\"donut__seg donut__seg--3\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"#BFD9F2\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"50.27 201.06\" stroke-dashoffset=\"-201.07\" />\n </g>\n </svg>\n {{#if showCenterLabel}}\n <span class=\"donut__center\">\n <strong class=\"donut__total\">100%</strong>\n <span class=\"donut__total-label\">total</span>\n </span>\n {{/if}}\n <ul class=\"donut__legend\">\n <li class=\"donut__item donut__item--1\"><span class=\"donut__swatch donut__swatch--1\" aria-hidden=\"true\"></span>Segment A — 48%<span class=\"donut__flag\">highlighted</span></li>\n <li class=\"donut__item donut__item--2\"><span class=\"donut__swatch donut__swatch--2\" aria-hidden=\"true\"></span>Segment B — 32%<span class=\"donut__flag\">highlighted</span></li>\n <li class=\"donut__item donut__item--3\"><span class=\"donut__swatch donut__swatch--3\" aria-hidden=\"true\"></span>Segment C — 20%<span class=\"donut__flag\">highlighted</span></li>\n </ul>\n <table class=\"donut__srtable\">\n <caption>Donut chart data</caption>\n <thead><tr><th scope=\"col\">Segment</th><th scope=\"col\">Share</th></tr></thead>\n <tbody>\n <tr><th scope=\"row\">Segment A</th><td>48%</td></tr>\n <tr><th scope=\"row\">Segment B</th><td>32%</td></tr>\n <tr><th scope=\"row\">Segment C</th><td>20%</td></tr>\n </tbody>\n </table>\n</div>\n<style>\n.donut { font: 14px/1.4 system-ui, sans-serif; color: #241430; max-width: 320px; position: relative; }\n.donut__ring { display: block; margin: 0 auto; }\n@media (prefers-reduced-motion: no-preference) {\n.donut__seg { transition: stroke-width .15s ease; }\n}\n.donut__center { position: absolute; top: 70px; left: 70px; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; text-align: center; }\n.donut__total { font-size: 20px; }\n.donut__total-label { font-size: 11px; color: #241430aa; }\n.donut__legend { list-style: none; margin: 12px 0 0; padding: 0; font-size: 13px; }\n.donut__item { display: flex; align-items: center; gap: 8px; padding: 3px 0; }\n.donut__swatch { width: 12px; height: 12px; border-radius: 3px; flex: none; }\n.donut__swatch--1 { background: {{accent}}; }\n.donut__swatch--2 { background: #D9C8F0; background-image: repeating-linear-gradient(45deg, #241430 0 2px, transparent 2px 5px); }\n.donut__swatch--3 { background: #BFD9F2; background-image: radial-gradient(#241430 1px, transparent 1px); background-size: 5px 5px; }\n.donut__flag { display: none; margin-left: 4px; font-weight: 700; font-size: 11px; }\n.donut__srtable { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }\n.donut--first .donut__seg--1 { stroke-width: calc(var(--t) + 6); }\n.donut--first .donut__item--1 .donut__flag { display: inline; }\n.donut--second .donut__seg--2 { stroke-width: calc(var(--t) + 6); }\n.donut--second .donut__item--2 .donut__flag { display: inline; }\n.donut--third .donut__seg--3 { stroke-width: calc(var(--t) + 6); }\n.donut--third .donut__item--3 .donut__flag { display: inline; }\n</style>", "tailwind": "<div class=\"donut-tw donut-tw--{{highlightSegment}} relative max-w-xs font-sans text-sm\" style=\"--t:{{thickness}};--accent:{{accent}};\">\n <svg class=\"block mx-auto\" width=\"140\" height=\"140\" viewBox=\"0 0 120 120\" aria-hidden=\"true\">\n <g transform=\"rotate(-90 60 60)\">\n <circle class=\"donut-tw__seg donut-tw__seg--1\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"120.64 130.69\" stroke-dashoffset=\"0\" />\n <circle class=\"donut-tw__seg donut-tw__seg--2\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"#D9C8F0\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"80.43 170.9\" stroke-dashoffset=\"-120.64\" />\n <circle class=\"donut-tw__seg donut-tw__seg--3\" cx=\"60\" cy=\"60\" r=\"40\" fill=\"none\" stroke=\"#BFD9F2\" stroke-width=\"{{thickness}}\" stroke-dasharray=\"50.27 201.06\" stroke-dashoffset=\"-201.07\" />\n </g>\n </svg>\n {{#if showCenterLabel}}\n <span class=\"absolute flex flex-col items-center text-center\" style=\"top:70px;left:70px;transform:translate(-50%,-50%);\">\n <strong class=\"text-xl\">100%</strong>\n <span class=\"text-[11px] text-[#241430aa]\">total</span>\n </span>\n {{/if}}\n <ul class=\"list-none m-0 mt-3 p-0 text-[13px]\">\n <li class=\"donut-tw__item donut-tw__item--1 flex items-center gap-2 py-[3px]\"><span class=\"w-3 h-3 rounded\" style=\"background:{{accent}}\" aria-hidden=\"true\"></span>Segment A — 48%<span class=\"donut-tw__flag hidden ml-1 font-bold text-[11px]\">highlighted</span></li>\n <li class=\"donut-tw__item donut-tw__item--2 flex items-center gap-2 py-[3px]\"><span class=\"w-3 h-3 rounded\" style=\"background:#D9C8F0;background-image:repeating-linear-gradient(45deg,#241430 0 2px,transparent 2px 5px)\" aria-hidden=\"true\"></span>Segment B — 32%<span class=\"donut-tw__flag hidden ml-1 font-bold text-[11px]\">highlighted</span></li>\n <li class=\"donut-tw__item donut-tw__item--3 flex items-center gap-2 py-[3px]\"><span class=\"w-3 h-3 rounded\" style=\"background:#BFD9F2;background-image:radial-gradient(#241430 1px,transparent 1px);background-size:5px 5px\" aria-hidden=\"true\"></span>Segment C — 20%<span class=\"donut-tw__flag hidden ml-1 font-bold text-[11px]\">highlighted</span></li>\n </ul>\n <table class=\"absolute w-px h-px overflow-hidden\" style=\"clip:rect(0 0 0 0)\">\n <caption>Donut chart data</caption>\n <thead><tr><th scope=\"col\">Segment</th><th scope=\"col\">Share</th></tr></thead>\n <tbody>\n <tr><th scope=\"row\">Segment A</th><td>48%</td></tr>\n <tr><th scope=\"row\">Segment B</th><td>32%</td></tr>\n <tr><th scope=\"row\">Segment C</th><td>20%</td></tr>\n </tbody>\n </table>\n</div>\n<style>\n@media (prefers-reduced-motion: no-preference) {\n.donut-tw__seg { transition: stroke-width .15s ease; }\n}\n.donut-tw--first .donut-tw__seg--1 { stroke-width: calc(var(--t) + 6); }\n.donut-tw--first .donut-tw__item--1 .donut-tw__flag { display: inline; }\n.donut-tw--second .donut-tw__seg--2 { stroke-width: calc(var(--t) + 6); }\n.donut-tw--second .donut-tw__item--2 .donut-tw__flag { display: inline; }\n.donut-tw--third .donut-tw__seg--3 { stroke-width: calc(var(--t) + 6); }\n.donut-tw--third .donut-tw__item--3 .donut-tw__flag { display: inline; }\n</style>", "react": "export function DonutChart({\n highlightSegment = \"{{highlightSegment}}\",\n thickness = {{thickness}},\n accent = \"{{accent}}\",\n showCenterLabel = {{showCenterLabel}},\n}) {\n const segs = [\n { key: \"1\", name: \"Segment A\", pct: 48, color: accent, len: 120.64, gap: 130.69, offset: 0 },\n { key: \"2\", name: \"Segment B\", pct: 32, color: \"#D9C8F0\", len: 80.43, gap: 170.9, offset: -120.64 },\n { key: \"3\", name: \"Segment C\", pct: 20, color: \"#BFD9F2\", len: 50.27, gap: 201.06, offset: -201.07 },\n ];\n const highlightIndex = { first: \"1\", second: \"2\", third: \"3\" }[highlightSegment] ?? \"1\";\n return (\n <div style={{ fontFamily: \"system-ui, sans-serif\", color: \"#241430\", maxWidth: 320, position: \"relative\", fontSize: 14 }}>\n <svg width={140} height={140} viewBox=\"0 0 120 120\" aria-hidden=\"true\" style={{ display: \"block\", margin: \"0 auto\" }}>\n <g transform=\"rotate(-90 60 60)\">\n {segs.map((s) => (\n <circle key={s.key} cx={60} cy={60} r={40} fill=\"none\" stroke={s.color}\n strokeWidth={s.key === highlightIndex ? thickness + 6 : thickness}\n strokeDasharray={`${s.len} ${s.gap}`} strokeDashoffset={s.offset} />\n ))}\n </g>\n </svg>\n {showCenterLabel && (\n <span style={{ position: \"absolute\", top: 70, left: 70, transform: \"translate(-50%, -50%)\", display: \"flex\", flexDirection: \"column\", alignItems: \"center\", textAlign: \"center\" }}>\n <strong style={{ fontSize: 20 }}>100%</strong>\n <span style={{ fontSize: 11, color: \"#241430aa\" }}>total</span>\n </span>\n )}\n <ul style={{ listStyle: \"none\", margin: \"12px 0 0\", padding: 0, fontSize: 13 }}>\n {segs.map((s) => (\n <li key={s.key} style={{ display: \"flex\", alignItems: \"center\", gap: 8, padding: \"3px 0\" }}>\n <span aria-hidden=\"true\" style={{ width: 12, height: 12, borderRadius: 3, background: s.color }} />\n {s.name} — {s.pct}%\n {s.key === highlightIndex && <span style={{ marginLeft: 4, fontWeight: 700, fontSize: 11 }}>highlighted</span>}\n </li>\n ))}\n </ul>\n <table style={{ position: \"absolute\", width: 1, height: 1, overflow: \"hidden\", clip: \"rect(0 0 0 0)\" }}>\n <caption>Donut chart data</caption>\n <thead><tr><th scope=\"col\">Segment</th><th scope=\"col\">Share</th></tr></thead>\n <tbody>\n {segs.map((s) => (\n <tr key={s.key}><th scope=\"row\">{s.name}</th><td>{s.pct}%</td></tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}" }
Save
History