RadialChart
Radial bars and gauges, with tracks, labels along the arc and a center value.
Simple
One ring per row, each arc sized by its value, over a track.
January - June 2024
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser"
innerRadius={30} outerRadius={110} background
tooltip={{ hideLabel: true, nameKey: "browser" }} />Usage
import { RadialChart } from "@elements/ui/chart-radial";
import type { ChartConfig } from "@elements/ui/chart";
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30} background />
<!-- a gauge -->
<RadialChart data={[{ task: "done", done: 64 }]} {config} value="done" name="task"
max={100} startAngle={90} endAngle={-270} innerRadius="70%" background
cornerRadius={12} centerValue="64%" centerLabel="complete" />Examples
Label
Each arc's name written along it from its start.
January - June 2024
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser"
startAngle={-90} endAngle={380} innerRadius={30} outerRadius={110} background
labels={{ position: "insideStart", key: "browser" }}
tooltip={{ hideLabel: true, nameKey: "browser" }} />Grid
grid draws a circle through each ring.
January - June 2024
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser"
innerRadius={30} outerRadius={100} grid tooltip={{ hideLabel: true, nameKey: "browser" }} />Text
A single arc to 250 degrees with rounded ends and its value in the center.
January - June 2024
| Browser | Visitors |
|---|---|
| Safari | 200 |
Code
<RadialChart data={[{ browser: "safari", visitors: 200, fill: "var(--color-safari)" }]}
config={browserConfig} value="visitors" name="browser"
startAngle={0} endAngle={250} innerRadius={80} outerRadius={110}
background cornerRadius={10} grid={{ radii: [86, 74], filled: true }}
centerValue="200" centerLabel="Visitors" tooltip={false} />Shape
A short arc over a filled grid track.
January - June 2024
| Browser | Visitors |
|---|---|
| Safari | 1,260 |
Code
<RadialChart data={[{ browser: "safari", visitors: 1260, fill: "var(--color-safari)" }]}
config={browserConfig} value="visitors" name="browser"
endAngle={100} innerRadius={80} outerRadius={140}
background grid={{ radii: [86, 74], filled: true }}
centerValue="1,260" centerLabel="Visitors" tooltip={false} />Stacked
Two value keys stacked along a half circle, with rounded ends and a gap between them.
January - June 2024
| Mobile | Desktop | |
|---|---|---|
| 1 | 570 | 1,260 |
Code
<RadialChart data={[{ month: "january", mobile: 570, desktop: 1260 }]} {config}
value={["mobile", "desktop"]} stack endAngle={180}
innerRadius={80} outerRadius={110} cornerRadius={5} separator
centerValue="1,830" centerLabel="Visitors" tooltip={{ hideLabel: true }} />Reverse stack order
reverseStackOrder stacks the last value key first, so the first ends the arc; the legend and tooltip keep value order.
- Mobile
- Desktop
| Mobile | Desktop | |
|---|---|---|
| 1 | 570 | 1,260 |
Code
<!-- desktop starts the arc, mobile ends it; legend and tooltip keep value order -->
<RadialChart data={[{ month: "january", mobile: 570, desktop: 1260 }]} {config}
value={["mobile", "desktop"]} stack reverseStackOrder endAngle={180}
innerRadius={80} outerRadius={110} cornerRadius={5} legend />Gauge
max fixes the scale, so a value reads as progress; the arc runs clockwise from twelve o'clock.
| Task | Done |
|---|---|
| Done | 64 |
Code
<RadialChart data={[{ task: "done", done: state.progress }]} config={{ done: { label: "Done" } }}
value="done" name="task" max={100} startAngle={90} endAngle={-270}
innerRadius="70%" outerRadius="95%" background cornerRadius={12}
centerValue={`${state.progress}%`} centerLabel="complete" />Ring size and gaps
Two value keys sit side by side in each ring; barSize fixes their thickness and barGap the space between them.
- Desktop
- Mobile
| Month | Desktop | Mobile |
|---|---|---|
| january | 186 | 80 |
| february | 305 | 200 |
| march | 237 | 120 |
Code
<!-- two value keys side by side in each ring -->
<RadialChart data={rows} {config} value={["desktop", "mobile"]} name="month"
innerRadius={24} barSize={10} barGap={6} legend />Minimum angle
A tiny value still gets an arc long enough to see and point at.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 3 |
| Other | 90 |
Code
<!-- edge has 3 visitors: minAngle keeps its arc 20 degrees long -->
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30} minAngle={20} />Small bars and corners
minPointSize gives every present value, zero included, a least sweep; cornerIsExternal rounds the ends outside the bar; forceCornerRadius draws a bar too short for its corners as a dot.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 0 |
| Firefox | 3 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 0 |
| Firefox | 3 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 0 |
| Firefox | 3 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 0 |
| Firefox | 3 |
Code
<!-- minPointSize: every present value, zero too, sweeps at least 12 degrees -->
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30} max={400} minPointSize={12} />
<!-- cornerIsExternal: the round ends reach past the start and end angles -->
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30} cornerRadius={10} cornerIsExternal />
<!-- forceCornerRadius: a bar too short for its corners is a round dot -->
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30} cornerRadius={10} forceCornerRadius />Center and margin
margin insets the plot, then cx and cy place the center as px or a percentage of what is left; the radius is half the inset box's shorter side.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30}
margin={{ left: 40 }} cx="40%" cy="60%" />Animation timing
animation sets when the marks start moving, how long they take and their easing: a CSS easing name, a cubic-bezier, spring, or a function of progress.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<!-- wait 150ms, then take 900ms to enter or move to new data -->
<RadialChart data={rows} {config} value="visitors" name="browser" innerRadius={30}
animation={{ begin: 150, duration: 900, easing: "spring" }} />Legend and tooltip types
legendType on a config entry sets that item's legend icon, and none leaves it out of the legend; tooltipType none shows no tooltip for it. On the value key they apply to every item.
- Chrome
- Safari
- Firefox
- Edge
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<!-- safari's legend icon is a circle; firefox has no tooltip; other has no legend item -->
<RadialChart data={rows} value="visitors" name="browser" innerRadius={30} legend config={{
...config,
safari: { label: "Safari", color: "var(--chart-2)", legendType: "circle" },
firefox: { label: "Firefox", color: "var(--chart-3)", tooltipType: "none" },
other: { label: "Other", color: "var(--chart-5)", legendType: "none" },
}} />Toggles, keyboard and table
Tab to the chart, arrows move through the rings; the legend hides rows; the table shows the data.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser"
innerRadius={30} background legend={{ toggle: true }} hidden={state.hidden}
active={state.active} onActiveChange={() => state.changes++}
onItemClick={(i) => state.clicked = i} />Ring options
maxBarSize caps how thick a ring grows; stackOffset expand stacks every row to the end angle, so each reads as shares; activeShape outlines the ring under the pointer; a second angle axis gives a value key a scale of its own.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
| Month | Mobile | Desktop |
|---|---|---|
| january | 570 | 1,260 |
| february | 300 | 200 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
| Month | Mobile | Desktop |
|---|---|---|
| january | 570 | 1,260 |
Code
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser"
innerRadius={30} maxBarSize={6} />
<RadialChart data={rows} {config} value={["mobile", "desktop"]} stack stackOffset="expand" endAngle={180} />
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser" activeShape />
<!-- two value scales: mobile reaches the end at 600, desktop at 2,000 -->
<RadialChart data={rows} {config} value={["mobile", "desktop"]} name="month" endAngle={180}
angleAxis={[{ max: 2000 }, { series: ["mobile"], max: 600 }]} />Ring order, hidden bars and layout
radiusAxis gives the value keys it names a ring order of their own; hide leaves value keys out; layout centric makes each row a wedge whose value reaches out from the center.
| Month | Desktop | Mobile |
|---|---|---|
| January | 186 | 80 |
| February | 305 | 200 |
| March | 237 | 120 |
| April | 73 | 190 |
| May | 209 | 130 |
| June | 214 | 140 |
| Month | Desktop | Mobile |
|---|---|---|
| January | 186 | 80 |
| February | 305 | 200 |
| March | 237 | 120 |
| April | 73 | 190 |
| May | 209 | 130 |
| June | 214 | 140 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<!-- mobile's rings run the other way: January outermost -->
<RadialChart data={rows} {config} value={["desktop", "mobile"]} name="month"
radiusAxis={[{}, { series: ["mobile"], reversed: true }]} />
<!-- mobile is not drawn; the tooltip lists desktop alone -->
<RadialChart data={rows} {config} value={["desktop", "mobile"]} name="month" hide={["mobile"]} />
<!-- each browser a wedge of the turn, its value out from the center -->
<RadialChart data={browsers} config={browserConfig} value="visitors" name="browser" layout="centric" />Moving to new data
animation matchBy pairs old and new bars by a key, so each browser keeps its color and turns to its new place; interpolate draws every frame with a function of your own, here one that sweeps each from its start angle.
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
| Browser | Visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
Code
<!-- each browser keeps its bar as the order turns -->
<RadialChart data={rows} {config} value="visitors" name="browser" animation={{ matchBy: matchByDataKey("browser") }} />
<!-- (items, t) => the bars to draw: each sweeps from its start angle -->
<RadialChart data={rows} {config} value="visitors" name="browser" animation={{ interpolate: sweep }} />