Donut Chart

Shows how parts make up a whole as a ring.

Revenue$97,900 
Monthly revenue by source data
SegmentValueShare
Subscriptions$48,20049.2%
Usage$26,40027.0%
Services$12,90013.2%
Marketplace$7,3007.5%
Other$3,1003.2%

Installation

pnpm dlx shadcn@latest add @paneui/donut-chart

Usage

Examples

Legend Below

Custom Colors

Thin Ring

Descriptions

Controlled

Keyboard

Each segment is a tab stop. Arrow keys cycle between segments, Esc blurs. The centre readout and legend follow the focused segment, and a hidden table mirrors the data for screen readers.

Motion

With reduced motion, segments appear at once instead of drawing in.

API Reference

DonutChart

Also accepts every prop of div.

segments*
{ id: string; label: string; value: number; color?: string; description?: string }[]
Slices in order. Non-positive values are skipped. description shows under the label in the legend and is read with the segment.
label= "Donut chart"
string
Accessible name of the chart.
thickness= 22
number
Ring thickness in viewBox units (the box is 200×200).
gap= 4
number
Gap between segments in viewBox units. Ends are rounded when every segment is long enough for round caps; otherwise all ends are square, so small segments never overlap their neighbours.
formatValue= formatNumber
(value: number) => string
Formats values in the centre, legend and tooltip.
totalLabel= the locale's
string
Centre caption when nothing is hovered.
maxSize= 240
number
Max ring diameter in px; it shrinks with its container.
showLegend= true
boolean
Show the value / share legend.
legendPosition= "side"
"side" | "bottom"
side sits beside the ring from the sm breakpoint.
activeId
string | null
Controlled highlighted segment.
defaultActiveId
string | null
Initially highlighted segment.
onActiveChange
(id: string | null) => void
Called on hover, focus and leave.
PropTypeDefaultDescription
segments*{ id: string; label: string; value: number; color?: string; description?: string }[]—Slices in order. Non-positive values are skipped. description shows under the label in the legend and is read with the segment.
labelstring"Donut chart"Accessible name of the chart.
thicknessnumber22Ring thickness in viewBox units (the box is 200×200).
gapnumber4Gap between segments in viewBox units. Ends are rounded when every segment is long enough for round caps; otherwise all ends are square, so small segments never overlap their neighbours.
formatValue(value: number) => stringformatNumberFormats values in the centre, legend and tooltip.
totalLabelstringthe locale'sCentre caption when nothing is hovered.
maxSizenumber240Max ring diameter in px; it shrinks with its container.
showLegendbooleantrueShow the value / share legend.
legendPosition"side" | "bottom""side"side sits beside the ring from the sm breakpoint.
activeIdstring | null—Controlled highlighted segment.
defaultActiveIdstring | null—Initially highlighted segment.
onActiveChange(id: string | null) => void—Called on hover, focus and leave.