Yugen UI

DonutChart

DonutChart gives a quick part-to-whole view with up to 6 slices; the tail is grouped into “Other” and the total sits in the middle.

A thin ring with parallel 2px surface gaps between slices, starting at 12 o'clock and going clockwise. The legend sits beside it with percentages (following the page's text direction); hover or use the arrow keys to see values. To compare values that are close together, use BarChart.
Yugen Labs · experimentalThis component is outside SemVer: its API can change in a minor release, and What's new says so. Versioning policy
Customer sources
October
  • Search42%
  • Social28%
  • Referral18%
  • Email12%

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { DonutChart } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Orders by city
  • Tokyo33%
  • Osaka29.4%
  • Kyoto10.7%
  • Yokohama8.5%
  • Nagoya6.6%
  • Other11.9%

Grouping the tail into “Other”

9 groups → the 5 largest + “Other” in neutral gray. The data table shows the grouped figure too.

Storage
  • Videos46.6%
  • Photos36.4%
  • Documents10.2%
  • Apps6.8%

Custom center label

centerValue / centerLabel replace the default total; size and thickness change the size of the ring.

Usage

Do
  • Use it only for a quick part-to-whole view with ≤ 6 slices; keep colors tied to entities (pass color when the data changes).
  • Put the most important number in the middle of the ring.
Don't
  • Don't use a donut to compare values that are close together. Use BarChart or show the numbers.
  • Don't use a 2-slice donut. Use StatTile or ProgressBar.
  • Don't give “Other” a categorical color. It is always neutral gray.

Props

Prop · TypeDefaultDescription
data{ label, value, color? }[]Default: —Values ≤ 0 are skipped.
maxSlicesnumberDefault: 6Maximum number of slices (“Other” included), never more than 6.
otherLabelstringDefault: "Other"Label of the grouped slice.
centerValue / centerLabelReactNodeDefault: total / "Total"Content in the middle of the ring.
size / thicknessnumberDefault: 200 / 12% sizeRing diameter and thickness (px).
legendbooleanDefault: trueLegend with percentages beside the ring.
valueFormat, locale, title, description, texture……Default: —Same as BarChart.

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.chart

Key · TypeDefault (English)messagesVi
roleDescriptionstring

aria-roledescription của vùng vẽ.

Default (English)"chart"messagesVi"biểu đồ"
heatmapRoleDescriptionstringDefault (English)"heat map"messagesVi"bản đồ nhiệt"
dataTablestring

Nút bật chế độ bảng của ChartContainer.

Default (English)"Data table"messagesVi"Bảng dữ liệu"
totalstring

Dòng tổng (tooltip, bảng) và nhãn giữa vòng DonutChart.

Default (English)"Total"messagesVi"Tổng"
valuestringDefault (English)"Value"messagesVi"Giá trị"
sharestringDefault (English)"Share"messagesVi"Tỉ lệ"
noDatastringDefault (English)"No data"messagesVi"Không có dữ liệu"
timestring

Tiêu đề cột đầu của bảng (khi không truyền indexLabel).

Default (English)"Time"messagesVi"Thời gian"
categorystringDefault (English)"Category"messagesVi"Danh mục"
groupstringDefault (English)"Group"messagesVi"Nhóm"
namestringDefault (English)"Name"messagesVi"Tên"
otherstring

Nhóm gộp (DonutChart vượt maxSlices, ScatterChart nhóm thứ 9+).

Default (English)"Other"messagesVi"Khác"
trendstring

Nút bật đường xu hướng của ScatterChart.

Default (English)"Trend"messagesVi"Xu hướng"
increasestringDefault (English)"Increase"messagesVi"Tăng"
decreasestringDefault (English)"Decrease"messagesVi"Giảm"
noChangestringDefault (English)"No change"messagesVi"Không đổi"
brushstring

ChartBrush: tên cửa sổ thu phóng, dòng "Đang xem … · n/N mốc", nút đặt lại.

Default (English)"Visible range"messagesVi"Vùng xem"
brushRoleDescriptionstringDefault (English)"zoom window"messagesVi"cửa sổ thu phóng"
brushViewingstringDefault (English)"Showing"messagesVi"Đang xem"
brushPoints(shown: number, total: number) => stringDefault (English)(shown, total) => `${shown}/${total} ${total === 1 ? "point" : "points"}`messagesVi(shown, total) => `${shown}/${total} mốc`
brushResetstringDefault (English)"Reset"messagesVi"Đặt lại"
lineSummary(info: { kind: "line" | "area" | "stacked" | "expand"; points: number; /** Mốc đầu / cuối (chỉ có khi points > 0). */ from?: string; to?: string; series: string[]; }) => string

Mô tả truy cập tự sinh (khi không truyền ariaLabel).

Default (English)Function, see messages.tsmessagesViFunction, see messages.ts
barSummary(info: { horizontal: boolean; stacked: boolean; categories: number; series: string[] }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
donutSummary(info: { groups: number; total: string; largest?: { label: string; share: string } }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
scatterSummary(info: { points: number; x: string; y: string; /** Tên đại lượng kích thước (biểu đồ bong bóng). */ size?: string; /** Tên các nhóm (khi có nhiều nhóm). */ groups?: string[]; trends: { group?: string; slope: string; r2: string }[]; }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
heatmapSummary(info: { rows: number; columns: number; min?: string; max?: string; hasEmpty: boolean }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
sparklineSummary(info: { points: number; first: string; last: string; min: string; max: string }) => stringDefault (English)Function, see messages.tsmessagesVi({ points, first, last, min, max }) => `Xu hướng ${points} điểm: từ ${first} đến ${last}, thấp nhất ${min}, cao nhất ${max}`