Radar Chart
Multi-axis radial comparison.
Balanced profile scores out of 100
| Metric | Score |
| Speed | 70 |
| Quality | 65 |
| Cost | 75 |
| Reach | 68 |
| Ease | 72 |
Specialised profile scores out of 100
| Metric | Score |
| Speed | 95 |
| Quality | 40 |
| Cost | 30 |
| Reach | 85 |
| Ease | 45 |
html
<div class="radar-chart radar-chart--balanced radar-chart--grid radar-chart--values" style="--accent:#D9C8F0;--sw:2;">
<svg class="radar-chart__svg" viewBox="0 0 140 135" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Radar chart of a balanced profile across 5 metrics: speed, quality, cost, reach and ease">
<g class="rc-gridwrap">
<polygon class="rc-grid" points="70,15 122.3,53 102.3,114.5 37.7,114.5 17.7,53"></polygon>
<polygon class="rc-grid" points="70,42.5 96.15,61.5 86.15,92.25 53.85,92.25 43.85,61.5"></polygon>
<line class="rc-spoke" x1="70" y1="70" x2="70" y2="15"></line>
<line class="rc-spoke" x1="70" y1="70" x2="122.3" y2="53"></line>
<line class="rc-spoke" x1="70" y1="70" x2="102.3" y2="114.5"></line>
<line class="rc-spoke" x1="70" y1="70" x2="37.7" y2="114.5"></line>
<line class="rc-spoke" x1="70" y1="70" x2="17.7" y2="53"></line>
</g>
<text class="rc-axis-label" x="70" y="8">Speed</text>
<text class="rc-axis-label" x="131.8" y="49.9">Quality</text>
<text class="rc-axis-label" x="108.2" y="126">Cost</text>
<text class="rc-axis-label" x="31.8" y="126">Reach</text>
<text class="rc-axis-label" x="8.2" y="49.9">Ease</text>
<polygon class="rc-poly rc-poly--balanced" points="70,31.5 104,58.95 94.25,103.37 48.01,100.26 32.34,57.76"></polygon>
<polygon class="rc-poly rc-poly--specialised" points="70,17.75 90.92,63.2 79.70,83.35 42.51,107.82 46.47,62.35"></polygon>
<text class="rc-value rc-value--balanced" x="70" y="20">70</text>
<text class="rc-value rc-value--balanced" x="112" y="55">65</text>
<text class="rc-value rc-value--balanced" x="100" y="110">75</text>
<text class="rc-value rc-value--balanced" x="40" y="107">68</text>
<text class="rc-value rc-value--balanced" x="24" y="55">72</text>
<text class="rc-value rc-value--specialised" x="70" y="6">95</text>
<text class="rc-value rc-value--specialised" x="98" y="60">40</text>
<text class="rc-value rc-value--specialised" x="82" y="90">30</text>
<text class="rc-value rc-value--specialised" x="34" y="114">85</text>
<text class="rc-value rc-value--specialised" x="36" y="58">45</text>
</svg>
<div class="rc-srtable-wrap rc-srtable-wrap--balanced">
<table class="radar-chart__srtable">
<caption>Balanced profile scores out of 100</caption>
<thead><tr><th scope="col">Metric</th><th scope="col">Score</th></tr></thead>
<tbody>
<tr><td>Speed</td><td>70</td></tr>
<tr><td>Quality</td><td>65</td></tr>
<tr><td>Cost</td><td>75</td></tr>
<tr><td>Reach</td><td>68</td></tr>
<tr><td>Ease</td><td>72</td></tr>
</tbody>
</table></div>
<div class="rc-srtable-wrap rc-srtable-wrap--specialised">
<table class="radar-chart__srtable">
<caption>Specialised profile scores out of 100</caption>
<thead><tr><th scope="col">Metric</th><th scope="col">Score</th></tr></thead>
<tbody>
<tr><td>Speed</td><td>95</td></tr>
<tr><td>Quality</td><td>40</td></tr>
<tr><td>Cost</td><td>30</td></tr>
<tr><td>Reach</td><td>85</td></tr>
<tr><td>Ease</td><td>45</td></tr>
</tbody>
</table></div>
</div>
<style>
.radar-chart { max-width: 320px; font: 11px system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 12px; box-sizing: border-box; }
.radar-chart__svg { width: 100%; height: auto; display: block; }
.radar-chart .rc-grid { fill: none; stroke: #24143022; stroke-width: 1; }
.radar-chart .rc-spoke { stroke: #24143022; stroke-width: 1; }
.radar-chart .rc-gridwrap { display: none; }
.radar-chart--grid .rc-gridwrap { display: block; }
.radar-chart .rc-axis-label { font-size: 8.5px; fill: #241430; text-anchor: middle; font-weight: 600; }
.radar-chart .rc-poly { fill: var(--accent); fill-opacity: .38; stroke: var(--accent); stroke-width: var(--sw); stroke-linejoin: round; display: none; }
.radar-chart--balanced .rc-poly--balanced { display: block; }
.radar-chart--specialised .rc-poly--specialised { display: block; }
.radar-chart .rc-value { font-size: 7.5px; fill: #241430; text-anchor: middle; font-weight: 700; display: none; }
.radar-chart--balanced.radar-chart--values .rc-value--balanced { display: block; }
.radar-chart--specialised.radar-chart--values .rc-value--specialised { display: block; }
.radar-chart .rc-srtable-wrap { display: none; }
.radar-chart--balanced .rc-srtable-wrap--balanced { display: block; }
.radar-chart--specialised .rc-srtable-wrap--specialised { display: block; }
.radar-chart .rc-srtable { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
</style>
tailwind
<div class="radar-chart-tw radar-chart-tw--balanced radar-chart-tw--grid radar-chart-tw--values" style="--accent:#D9C8F0;--sw:2;">
<svg class="radar-chart-tw__svg" viewBox="0 0 140 135" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Radar chart of a balanced profile across 5 metrics: speed, quality, cost, reach and ease">
<g class="rc-gridwrap">
<polygon class="rc-grid" points="70,15 122.3,53 102.3,114.5 37.7,114.5 17.7,53"></polygon>
<polygon class="rc-grid" points="70,42.5 96.15,61.5 86.15,92.25 53.85,92.25 43.85,61.5"></polygon>
<line class="rc-spoke" x1="70" y1="70" x2="70" y2="15"></line>
<line class="rc-spoke" x1="70" y1="70" x2="122.3" y2="53"></line>
<line class="rc-spoke" x1="70" y1="70" x2="102.3" y2="114.5"></line>
<line class="rc-spoke" x1="70" y1="70" x2="37.7" y2="114.5"></line>
<line class="rc-spoke" x1="70" y1="70" x2="17.7" y2="53"></line>
</g>
<text class="rc-axis-label" x="70" y="8">Speed</text>
<text class="rc-axis-label" x="131.8" y="49.9">Quality</text>
<text class="rc-axis-label" x="108.2" y="126">Cost</text>
<text class="rc-axis-label" x="31.8" y="126">Reach</text>
<text class="rc-axis-label" x="8.2" y="49.9">Ease</text>
<polygon class="rc-poly rc-poly--balanced" points="70,31.5 104,58.95 94.25,103.37 48.01,100.26 32.34,57.76"></polygon>
<polygon class="rc-poly rc-poly--specialised" points="70,17.75 90.92,63.2 79.70,83.35 42.51,107.82 46.47,62.35"></polygon>
<text class="rc-value rc-value--balanced" x="70" y="20">70</text>
<text class="rc-value rc-value--balanced" x="112" y="55">65</text>
<text class="rc-value rc-value--balanced" x="100" y="110">75</text>
<text class="rc-value rc-value--balanced" x="40" y="107">68</text>
<text class="rc-value rc-value--balanced" x="24" y="55">72</text>
<text class="rc-value rc-value--specialised" x="70" y="6">95</text>
<text class="rc-value rc-value--specialised" x="98" y="60">40</text>
<text class="rc-value rc-value--specialised" x="82" y="90">30</text>
<text class="rc-value rc-value--specialised" x="34" y="114">85</text>
<text class="rc-value rc-value--specialised" x="36" y="58">45</text>
</svg>
<div class="rc-srtable-wrap rc-srtable-wrap--balanced">
<table class="radar-chart-tw__srtable">
<caption>Balanced profile scores out of 100</caption>
<thead><tr><th scope="col">Metric</th><th scope="col">Score</th></tr></thead>
<tbody>
<tr><td>Speed</td><td>70</td></tr>
<tr><td>Quality</td><td>65</td></tr>
<tr><td>Cost</td><td>75</td></tr>
<tr><td>Reach</td><td>68</td></tr>
<tr><td>Ease</td><td>72</td></tr>
</tbody>
</table></div>
<div class="rc-srtable-wrap rc-srtable-wrap--specialised">
<table class="radar-chart-tw__srtable">
<caption>Specialised profile scores out of 100</caption>
<thead><tr><th scope="col">Metric</th><th scope="col">Score</th></tr></thead>
<tbody>
<tr><td>Speed</td><td>95</td></tr>
<tr><td>Quality</td><td>40</td></tr>
<tr><td>Cost</td><td>30</td></tr>
<tr><td>Reach</td><td>85</td></tr>
<tr><td>Ease</td><td>45</td></tr>
</tbody>
</table></div>
</div>
<style>
.radar-chart-tw { max-width: 320px; font: 11px system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 12px; box-sizing: border-box; }
.radar-chart-tw__svg { width: 100%; height: auto; display: block; }
.radar-chart-tw .rc-grid { fill: none; stroke: #24143022; stroke-width: 1; }
.radar-chart-tw .rc-spoke { stroke: #24143022; stroke-width: 1; }
.radar-chart-tw .rc-gridwrap { display: none; }
.radar-chart-tw--grid .rc-gridwrap { display: block; }
.radar-chart-tw .rc-axis-label { font-size: 8.5px; fill: #241430; text-anchor: middle; font-weight: 600; }
.radar-chart-tw .rc-poly { fill: var(--accent); fill-opacity: .38; stroke: var(--accent); stroke-width: var(--sw); stroke-linejoin: round; display: none; }
.radar-chart-tw--balanced .rc-poly--balanced { display: block; }
.radar-chart-tw--specialised .rc-poly--specialised { display: block; }
.radar-chart-tw .rc-value { font-size: 7.5px; fill: #241430; text-anchor: middle; font-weight: 700; display: none; }
.radar-chart-tw--balanced.radar-chart-tw--values .rc-value--balanced { display: block; }
.radar-chart-tw--specialised.radar-chart-tw--values .rc-value--specialised { display: block; }
.radar-chart-tw .rc-srtable-wrap { display: none; }
.radar-chart-tw--balanced .rc-srtable-wrap--balanced { display: block; }
.radar-chart-tw--specialised .rc-srtable-wrap--specialised { display: block; }
.radar-chart-tw .rc-srtable { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
</style>
react
export function RadarChart({
profile = "balanced",
showGrid = true,
showValues = true,
strokeWidth = 2,
accent = "#D9C8F0",
}) {
const axes = [
{ label: "Speed", lx: 70, ly: 8 },
{ label: "Quality", lx: 131.8, ly: 49.9 },
{ label: "Cost", lx: 108.2, ly: 126 },
{ label: "Reach", lx: 31.8, ly: 126 },
{ label: "Ease", lx: 8.2, ly: 49.9 },
];
const profiles = {
balanced: {
points: "70,31.5 104,58.95 94.25,103.37 48.01,100.26 32.34,57.76",
values: [["70", "20", "70"], ["112", "55", "65"], ["100", "110", "75"], ["40", "107", "68"], ["24", "55", "72"]],
caption: "Balanced profile scores out of 100",
},
specialised: {
points: "70,17.75 90.92,63.2 79.70,83.35 42.51,107.82 46.47,62.35",
values: [["70", "6", "95"], ["98", "60", "40"], ["82", "90", "30"], ["34", "114", "85"], ["36", "58", "45"]],
caption: "Specialised profile scores out of 100",
},
};
const active = profiles[profile] ?? profiles.balanced;
return (
<div style={{ maxWidth: 320, padding: 12, font: "11px system-ui, sans-serif", color: "#241430", background: "#FAF7F2", boxSizing: "border-box" }}>
<svg viewBox="0 0 140 135" style={{ width: "100%", height: "auto", display: "block" }}
role="img" aria-label={`Radar chart of a ${profile} profile across 5 metrics: speed, quality, cost, reach and ease`}>
{showGrid && (
<g fill="none" stroke="#24143022" strokeWidth={1}>
<polygon points="70,15 122.3,53 102.3,114.5 37.7,114.5 17.7,53" />
<polygon points="70,42.5 96.15,61.5 86.15,92.25 53.85,92.25 43.85,61.5" />
{axes.map((a, i) => {
const outer = ["70,15", "122.3,53", "102.3,114.5", "37.7,114.5", "17.7,53"][i].split(",");
return <line key={i} x1={70} y1={70} x2={outer[0]} y2={outer[1]} />;
})}
</g>
)}
{axes.map((a, i) => (
<text key={i} x={a.lx} y={a.ly} fontSize={8.5} textAnchor="middle" fontWeight={600} fill="#241430">{a.label}</text>
))}
<polygon points={active.points} fill={accent} fillOpacity={0.38} stroke={accent} strokeWidth={strokeWidth} strokeLinejoin="round" />
{showValues && active.values.map(([x, y, v], i) => (
<text key={i} x={x} y={y} fontSize={7.5} textAnchor="middle" fontWeight={700} fill="#241430">{v}</text>
))}
</svg>
</div>
);
}