Donut Chart
Blocks & SlicesA hand-rolled SVG donut/ring chart whose slices sweep in clockwise on mount and lift on hover or legend focus, showing that slice's share in the center; the keyboard-operable legend pins a slice, and prefers-reduced-motion paints the full ring instantly with no sweep or lift.
Inspired by Watermelon UI — dashboard charts — independently built, not affiliated. Attribution policy
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/donut-chart.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/donut-chart.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div className="w-full max-w-[460px] px-2">
<DonutChart
data={[
{ label: "Direct", value: 4200 },
{ label: "Referral", value: 3100 },
{ label: "Organic", value: 2400 },
{ label: "Social", value: 1500 },
{ label: "Email", value: 900 },
]}
size={188}
thickness={24}
/>
</div>Props
DonutChartProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect">
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | DonutChartDatum[] | — | Slices to plot. Zero / negative values are dropped. |
| size | number | 200 | Outer diameter of the ring in pixels. Defaults to 200. |
| thickness | number | 26 | Ring stroke width in pixels (clamped to fit `size`). Defaults to 26. |
| centerLabel | React.ReactNode | — | Center content. Defaults to the formatted total with a "Total" caption. |
| valueFormatter | (n: number) => string | groupedInt | Formats legend values, the center total and aria text. Defaults to grouped integers. |