Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

DonutChart

  • Stable
  • WCAG 2.2 evidence
  • RTL

A donut chart: the parts of a whole as slices of a ring, with the total in the hole and a legend of rows that give every slice its value and share. Data driven: slices in, SVG out; the same props render the static SVG on the server. Accessibility: the figure is named by title, described by summary and backed by a data table with every value and share (WCAG 1.1.1, 1.3.1). The plot is ONE tab stop: any arrow key moves between slices (Right and Down go clockwise), Home and End jump to the first and last, and each slice is announced with its name, value and share. Hovering or focusing a slice lifts it outward and shows a tooltip that stays while hovered and closes with Escape (1.4.13, 2.1.1). Slices differ by colour AND fill pattern, and the legend rows repeat the pattern next to the name, value and share as text (1.4.1). The draw-in and the lift are behind motion-safe:. The donut is a fixed 240 px and the legend wraps under it on a narrow card (1.4.10); the plot stays left-to-right in right-to-left pages while the card, legend and table mirror, and digits follow the locale. Consumer duties: a title that asks the question, a summary with the main message, units in valueFormat, meaningful slice names; a donut is for a handful of parts of a whole, use a BarChart to compare many values precisely.

import { DonutChart } from "@nexera-ui/react";
Loading example…
15
examples
22
props
4
live controls
1
platform
9
WCAG criteria
1
block uses it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
isCenterHidden
title
description
isLegendHidden
Generated code
import { DonutChart } from "@nexera-ui/react";

<DonutChart />

Examples 14

The same examples as Storybook, rendered live. Open Code to copy one.

With table disclosure

The table is a disclosure under the plot by default, the visible text alternative of the chart.

Loading example…

Thin ring custom centre

A thinner ring (innerRadius) and your own wording for the hole.

Loading example…

Plot only

Without the legend rows and without the hole text: the slices stay named in the tooltip and the table.

Loading example…

Currency

Formats and units: currency with the locale, large numbers in the hole shrink to fit.

Loading example…

Loading

Loading, empty and error are ChartStates inside the card; the header stays.

Loading example…

Empty

Loading example…

Error state

Loading example…

Single slice

One slice closes into a full ring: 100 percent.

Loading example…

Zero and missing

A slice of 0 is not drawn but keeps its legend row and table row; a missing value reads "No data".

Loading example…

Many slices

Twelve slices cycle the eight colours and patterns; tiny slices read "<1%". Group the tail as "Other" in real use.

Loading example…

Long labels

Long slice names wrap in the legend rows, the tooltip and the table; nothing is cut off.

Loading example…

Pinned styles

Keep a slice's colour and pattern when you filter the list: styleIndex pins it.

Loading example…

Range switch

The header controls: a range switch that swaps the data, and a menu button in the actions slot.

Loading example…

Right to left

Right-to-left page: the card, legend rows and table mirror, the donut keeps its clockwise direction from 12 o'clock, digits follow the locale.

Loading example…

Props 22

Press "Try it" on a card to load that prop into the playground.

22 props shown

slices*Nexera
readonly DonutSlice[]

The slices, in the order they run clockwise from 12 o'clock. Keep to about eight: more cycle the colours and patterns and the smallest slices become thin; group the tail as "Other". Each slice gets its own colour AND fill pattern (WCAG 1.4.1), and its name, value and share are in the legend rows, the tooltip and the table.

Default –
innerRadiusNexera
number

Radius of the hole as a share of the outer radius, 0.2 to 0.9. A bigger hole is a thinner ring.

Default 0.7
centerValueNexera
ReactNode

The headline in the hole. A string or number shrinks to fit the hole.

Default the total of the slices, formatted
centerLabelNexera
ReactNode

The caption under the headline. Translate it.

Default Total
isCenterHiddenNexera
boolean

Leave the hole empty.

Default false
valueLabelNexera
string

Header of the value column of the table and label of the value row in the tooltip and the point labels. Translate it.

Default Value
shareLabelNexera
string

Header of the share column of the table and label of the share row in the tooltip and the point labels. Translate it.

Default Share
title*Nexera
string

Chart title: the question the chart answers ("Headcount"). Required: it names the figure, the plot and the data table (WCAG 1.1.1).

Default –
descriptionNexera
ReactNode

Secondary line under the title.

Default –
summary*Nexera
string

One or two sentences with what the chart shows and its main message ("Headcount grew from 96 to 128 over twelve months"). Required: it describes the figure for assistive technology (WCAG 1.1.1); the data table has the details.

Default –
rangeNexera
ChartRangeProps

Range switch in the header: 3M, 6M, 12M. Pass the data of the chosen range back in.

Default –
actionsNexera
ReactNode

Extra controls in the header, after the range switch.

Default –
kpiNexera
ChartKpiProps

KPI row above the plot: the headline number with an optional label or change badge.

Default –
stateNexera
ChartPlotState

The state that replaces the plot: loading (skeleton), empty or error. A chart without a value to plot shows the empty state by itself; pass { status: "empty", title, description, action } to give it your wording.

Default –
tableNexera
ChartTableOptions

The data table that is the text alternative: caption, first-column header and whether it is visible or only for assistive technology.

Default –
localeNexera
string

Locale of digits and separators.

Default the `NexeraProvider` locale
valueFormatNexera
NumberFormatOptions

Intl.NumberFormat options for values ({ style: "currency", currency: "PKR" }, { style: "percent" }). Serialisable, so it works from a Server Component; formatValue needs a Client Component.

Default –
formatValueNexera
(value: number) => string

Formats a value for tooltips, point labels and the table (full precision). Wins over valueFormat.

Default –
heightNexera
number

Height of the plot in px. The card grows with the header, KPI and legend around it.

Default 240
isLegendHiddenNexera
boolean

Hide the legend. The series stay named in the tooltip, the point labels and the table.

Default false
plotLabelNexera
string

Accessible name of the plot group. Translate it.

Default the chart `title`
noDataLabelNexera
string

Text for a missing value in the tooltip and the table. Translate it.

Default No data

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

8 direct · 1 supporting
  • 1.1.1Non-text ContentLevel A · tested directly
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.4.1Use of ColorLevel A · tested directly
  • 1.4.10ReflowLevel AA · tested directly
  • 1.4.13Content on Hover or FocusLevel AA · tested directly
  • 2.1.1KeyboardLevel A · tested directly
  • 2.3.3Animation from InteractionsLevel AAA · supporting test
  • 4.1.2Name, Role, ValueLevel A · tested directly
  • 4.1.3Status MessagesLevel AA · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

Usage
<DonutChart className="shadow-sm" />

Used in blocks

Related components