Donut Chart

Pro

Animated SVG donut plus a gradient variant with per-slice radial gradients and staggered entrance.

</>sv-donut-chart chartdonutproportion
import { SvDonutChartComponent } from '@styloviz-pro/charts';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

With title & size

Pro

Click a slice

Pro

When to use

  • Showing parts of a whole when there are only a few segments (≤6).
  • You want a center label/total in the donut hole.
  • For precise value comparison, a Bar Chart is easier to read than slices.

Async states

  • loading
  • empty
  • error
  • retry

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the series are being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
emptyMessagestring'No data to plot'Copy for the empty state.
filteredbooleanfalseWhether a filter, not an absence of data, is why the chart is empty.
slicesDonutSlice[][]Data slices.
valuePolicySvValuePolicy'omit'What to do with a slice this chart cannot plot — a negative value, `NaN`, `Infinity`. A donut divides by the sum of its values, so an unplottable one is not merely undrawable: left in the denominator it changes the angle of every OTHER slice, and the figure in the centre stops matching the ring. There is no "leave it alone" option for that reason. - `omit` (default) — drop it, and disclose the count and that the percentages are of the remainder. - `reject` — refuse the dataset and show the error state. `clamp` is not supported: a clamped slice is a 0° arc, which leaves nothing to mark, so it falls back to `omit` with a dev warning. `render` likewise.
titlestring''Chart title.
sizenumber220Size of the SVG square (width = height).
optionsDonutChartOptions{}Chart options.
customClassstring''Additional CSS classes on the root div.
ariaLabelstring''Accessible-name override for the chart image. When empty, a concise data summary is generated; the full data is exposed via a visually-hidden table.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
sliceSelectDonutSliceEmitted when a slice (arc or legend entry) is clicked.

<sv-gradient-donut-chart>

Also in this family — SvGradientDonutChartComponent from @styloviz-pro/charts.

Async states

  • loading
  • empty
  • error
  • retry

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the series are being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
emptyMessagestring'No data to plot'Copy for the empty state.
filteredbooleanfalseWhether a filter, not an absence of data, is why the chart is empty.
slicesGradientDonutSlice[][]Ring segments — `label`, absolute `value` and optional base `color` (a lighter gradient stop is derived from it). Shares are computed from the plottable values after `valuePolicy`; an empty or all-zero set shows the empty state.
valuePolicySvValuePolicy'omit'What to do with a slice this chart cannot plot — a negative value, `NaN`, `Infinity`. A donut divides by the sum of its values, so an unplottable one is not merely undrawable: left in the denominator it changes the angle of every OTHER slice, and the figure in the centre stops matching the ring. There is no "leave it alone" option for that reason. - `omit` (default) — drop it, and disclose the count and that the percentages are of the remainder. - `reject` — refuse the dataset and show the error state. `clamp` is not supported: a clamped slice is a 0° arc, which leaves nothing to mark, so it falls back to `omit` with a dev warning. `render` likewise.
titlestring''Chart title, rendered above the ring and used in the default accessible name; hidden when empty.
sizenumber240SVG viewBox size (width = height).
optionsGradientDonutOptions{}Slice order and long-tail folding, legend toggle, centre label/sub-label, ring thickness, slice gap and entrance animation duration — see `GradientDonutOptions`.
customClassstring''Extra CSS classes applied to the root wrapper.
ariaLabelstring''Accessible-name override; otherwise a per-segment summary is generated.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.

Wire it to your API

This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.

Template

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `slices`, `loading` and `error`.
  • Set `filtered` when a search or filter is active. It is the difference between "you have no orders" and "no orders match this filter" — telling a customer with 4,000 orders the first one reads as a bug.
  • Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.

Full walkthrough: Connecting to a backend.

Customization & theming

  • Solid or per-slice gradient fills. The shading is DECORATIVE — arc length is the whole of the data — and the gradient variant says so under the plot, because every other gradient in dataviz carries a value and a reader arrives trained to look for the second dimension.
  • `sliceOrder` keeps the host's order (default) or sorts largest first, which is the arrangement a ring is easiest to read in.
  • `groupBelow` and `maxSlices` fold the unreadable tail into one `Other` slice and disclose how many and what share. Off by default; a single small slice is never folded, since an `Other` of one is that slice with its name taken away.
  • Center label/total slot.
  • Configurable thickness and gap.
  • Handle `sliceSelect` (arc or legend click) for selection.
  • `valuePolicy` decides what happens to a segment this chart cannot plot — a negative, `NaN` or `Infinity`. A ring divides by the sum of its values, so an unplottable one is not merely undrawable: left in the denominator it changes the angle of every OTHER segment, which is why there is no "leave it alone" option. `omit` (default) drops it and says the percentages are of the remainder; `reject` refuses the dataset. `clamp` is not offered: a clamped segment is a 0° arc, which leaves nothing to mark, so a request for it falls back to `omit` with a dev warning.

Best practices

  • Do: Keep segments to a handful; merge small slices into "Other".
  • Do: Show values/percentages in the legend, not just colors.
  • Don't: Don't use a donut to compare many near-equal values — angles are hard to judge.

Accessibility

  • The ring, the arc labels, the centre readout and the legend all read the SAME resolved list. They did not: the arcs were built from the plotted slices while every label indexed the raw input, so the moment the value policy omitted one, index `i` named a different slice from the one it drew — an arc announcing its neighbour's label, and a legend entry whose hover highlighted the wrong wedge.
  • The SVG is a `role="group"` with a generated label listing each segment and its share (override via `ariaLabel`) — `group`, not `img`, because a slice can be a tab stop and an `img`'s subtree is pruned.
  • Arc angle is share and the raw value is nowhere else on the page, so `sv-data-summary-table` publishes segment, value and percentage — on both the solid and the gradient donut. No overview line: the generated name has already read every label with its share before the table begins, and what the table adds is the raw numbers and a structure to compare them in.
  • When the long tail is folded, the table lists every folded segment in its own row under `Other`, each marked `(in Other)`, which is what the fold notice promises. Because that table is for screen readers and never drawn, the visible notice also names the folded segments itself. `Other` is drawn in a neutral slate rather than the colour of the first segment it folded.
  • The center label is not a row. `centerLabel` renders as real SVG `<text>` inside the `group`, so it is already in the accessibility tree; repeating it would invent a segment that does not exist.
  • The legend conveys labels and values as text.
  • Whatever `valuePolicy` does to the data is stated in the rendered output, under the plot and under the empty state — how many segments were dropped, their real values, and that the shares are of what remains. A `console.warn` is not a disclosure: the person reading the dashboard never sees it.
  • A ring whose every value is zero shows the empty state rather than a blank circle, and the sentence beneath distinguishes "the data arrived and was all zero" from "the fetch returned nothing".

Feedback on Donut Chart

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.