Skip to content
Home Theme Gallery

Pie chart

The custom element is <hui-pie-chart>.

Overview

A pie, or with inner-radius a donut with its total in the hole, one slice per row. The defaults are Recharts', which shadcn's examples keep: from three o'clock, counter-clockwise, 80 percent of the room. The shadcn reference's savings ring is this element, clockwise from the top.

Example

A donut with its total and a legend
Source
<div style="max-width:15rem"><hui-pie-chart label="Browser share" inner-radius="50" legend center-label="935" center-caption="Visitors" style="height:220px">
<script type="application/json">{"series":[{"key":"visitors","label":"Visitors"}],"rows":[{"label":"Chrome","visitors":275},{"label":"Safari","visitors":200},{"label":"Firefox","visitors":287},{"label":"Edge","visitors":173}]}</script>
</hui-pie-chart></div>

The Go template that renders it:

<hui-pie-chart label="Browser share" inner-radius="50" legend center-label="{{ .Total }}" center-caption="Visitors" style="height:220px;max-width:15rem">
<script type="application/json">{{ .Browsers }}</script>
</hui-pie-chart>

On a phone

A legend wider than its chart wraps onto more lines, centred, and the plot gives up the height it needs. A hole set in pixels never takes more than 85 percent of the radius, so a donut squeezed by its legend is still a ring.

A legend with six rows 375 px wide
Source
<hui-pie-chart label="Visitors by browser" inner-radius="60" legend style="height:280px">
<script type="application/json">{"series":[{"key":"visitors","label":"Visitors"}],"rows":[{"label":"Chrome","visitors":275},{"label":"Safari","visitors":200},{"label":"Firefox","visitors":187},{"label":"Edge","visitors":173},{"label":"Samsung Internet","visitors":90},{"label":"Other","visitors":60}]}</script>
</hui-pie-chart>

API

Attributes14
Attributes
NameTypeDefaultDescription
labelstring""Required. The chart's accessible name, followed by the centre text, and the data table's caption.
indexstring"label"The row property that names each slice or ring.
start-anglenumber0Where the first arc starts, in degrees from three o'clock, counter-clockwise - Recharts' convention, so shadcn's values carry over.
end-anglenumber360Where a full sweep ends. Below the start angle, the chart runs clockwise.
inner-radiusnumber0The hole. Up to 1 a fraction of the room, above 1 pixels.
outer-radiusnumber0.8The outer edge, the same way.
gapnumber1The space between slices at their outer edge, in pixels. 0 lets them touch, as the reference's do.
center-labelstring-Large text in the middle - a total. Read after the label as part of the chart's name.
center-captionstring-Smaller, muted text beneath it.
legendbooleanfalseA legend of the rows under the chart.
tooltip"index" | "item" | "none""index"The row under the pointer, or no tooltip.
indicator"dot" | "line" | "dashed""dot"The marker beside the tooltip row.
formatstring-Intl.NumberFormat options as JSON.
localestringthe document's langThe locale values are formatted in.
Properties14
Properties
NameTypeDefaultDescription
labelstringas <code>label</code>Reflects to the label attribute.
indexstringas <code>index</code>Reflects to the index attribute.
startAnglenumberas <code>start-angle</code>Reflects to the start-angle attribute.
endAnglenumberas <code>end-angle</code>Reflects to the end-angle attribute.
innerRadiusnumberas <code>inner-radius</code>Reflects to the inner-radius attribute.
outerRadiusnumberas <code>outer-radius</code>Reflects to the outer-radius attribute.
gapnumberas <code>gap</code>Reflects to the gap attribute.
centerLabelstringas <code>center-label</code>Reflects to the center-label attribute.
centerCaptionstringas <code>center-caption</code>Reflects to the center-caption attribute.
legendbooleanas <code>legend</code>Reflects to the legend attribute.
tooltip"index" | "item" | "none"as <code>tooltip</code>Reflects to the tooltip attribute.
indicator"dot" | "line" | "dashed"as <code>indicator</code>Reflects to the indicator attribute.
formatstringas <code>format</code>Reflects to the format attribute.
localestringas <code>locale</code>Reflects to the locale attribute.
Events1
Events
NameDescription
hui-chart-focusThe reader moved to a category, by pointer or keyboard: its position, and the row as the server sent it. It bubbles and is composed. Announced, never stored: a host can mirror it elsewhere on the page.
Slots1
Slots
NameDescription
(default)One <script type="application/json"> holding series and rows. Replacing it, or its text, redraws the chart.
CSS custom properties2
CSS custom properties
NameDefaultDescription
--hui-chart-1 … --hui-chart-5the preset's violetSeries colours, by position, repeating after the fifth.
--hui-series-<key>-One series' colour, set from the host's stylesheet: --hui-series-mobile: var(--hui-chart-4). A colour field in the JSON wins over it.
::part() hooks8
::part() hooks
NameDescription
figureThe wrapper carrying role="figure" and the name.
plotThe <svg>, hidden from assistive technology.
markOne slice or ring, with data-index.
centre-labelThe text in the middle.
tableThe visually hidden data table.
tooltipThe tooltip, a manual popover.
legendThe legend of rows.
announcerThe visually hidden live region.

States

A progress ring, clockwise from the top

The same element as a progress ring: a hole from inner-radius, a sweep set by start-angle and end-angle, and a total in the middle.

A progress ring, clockwise from the top
Source
<div style="width:220px"><hui-pie-chart label="Savings goal" inner-radius="70" outer-radius="95" start-angle="90" end-angle="-270" center-label="$24,000" center-caption="80% of $30,000" style="height:220px">
<script type="application/json">{"series":[{"key":"amount","label":"Amount"}],"rows":[{"label":"Saved","amount":24000,"colour":"var(--hui-chart-2)"},{"label":"Remaining","amount":6000,"colour":"var(--hui-chart-1)"}]}</script>
</hui-pie-chart></div>

A pie

No inner-radius, so the slices meet in the centre.

A pie
Source
<div style="width:200px"><hui-pie-chart label="Browser share" style="height:200px">
<script type="application/json">{"series":[{"key":"visitors","label":"Visitors"}],"rows":[{"label":"Chrome","visitors":275},{"label":"Safari","visitors":200},{"label":"Firefox","visitors":287},{"label":"Edge","visitors":173}]}</script>
</hui-pie-chart></div>

Server-side mechanics

The server writes one row per slice or ring into the element's <script type="application/json"> child, in the order they are drawn: the chart never sorts, so the server decides whether the biggest slice comes first. A row may carry its own colour. Only the first series is drawn. Replacing the child redraws the same element without animating.

Accessibility

  • The chart is a figure named by its label and the centre text - "Browser share: 935 Visitors" - because the SVG, and so the text drawn in the hole, is hidden from assistive technology. The data is a visually hidden table.
  • The plot is one tab stop: the arrow keys step the slices or rings with the tooltip following, and a polite live region reads each - "Safari 200".
  • The first draw sweeps the arcs open over 1500ms after a 400ms pause, as the reference's do; under prefers-reduced-motion: reduce they are simply there.
  • Slices part by a pixel at their outer edge by default, so neighbours whose colours sit 1.3:1 apart still read as two; gap="0" matches the reference, where they touch.

Keyboard

Keyboard
KeysAction
TabFocuses the plot, one stop per chart, and shows the tooltip at the category the keyboard was last on.
Arrow Right, Arrow DownThe next category.
Arrow Left, Arrow UpThe previous category.
Home, EndThe first and the last category.
EscapeHides the tooltip; focus stays on the plot.

Gotchas

  • Give a pie a width as well as a height, or its wrapper one: a chart fills its container's width, and a pie is only as big as the smaller of the two.
  • A pie reads the first series only. A second series is ignored rather than drawn.
  • Like every chart, it ships in home-ui-charts.js.