Skip to main content

Pie

Info:Metrics
25

A pie or donut chart of parts against a whole, colored from a theme-derived palette, with an interactive readout.

pie chart donut doughnut parts of a whole share distribution

Live demo

live · @xtyle/astro

Pie

Pie and donut

Parts of a whole. Hover or focus a slice for its value and share; the donut carries the total.

42%30%18%10%
DirectSearchSocialReferral
Traffic by source
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%
2.5k
RentFoodTransitFun
Monthly budget
SliceValueShare
Rent120048%
Food60024%
Transit30012%
Fun40016%

One data set, five schemes

skittles

Skittles scheme
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%

accents

100
Accents scheme
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%

statuses

100
Statuses scheme
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%

thermal, reversed

Thermal reversed scheme
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%

status

100
Status scheme
SliceValueShare
Direct4242%
Search3030%
Social1818%
Referral1010%

Discrete outcomes

The statuses scheme colors each slice by a semantic tone (success, failed, warn, info, skipped, live), so a run-outcome breakdown reads by meaning. The right chart is a clean run with no failures or flakes: because each slice pins to its tone, the survivors keep their own colors instead of shifting down the scheme when categories drop out.

full breakdown

68%7%5%11%6%189
PassedFailedFlakySkippedRunningQueued
Test runs
SliceValueShare
Passed12868%
Failed147%
Flaky95%
Skipped2111%
Running63%
Queued116%

clean run (no failures)

86%10%177
PassedSkippedQueued
Clean run
SliceValueShare
Passed15286%
Skipped1810%
Queued74%

Empty state

A chart with nothing to plot (an empty set, or all-zero values) shows a muted No data message in place of the wedges, so a no-data period reads as intentional rather than broken.

No data
Requests by region
SliceValueShare
No data
Test runs
SliceValueShare

Pie plots a set of labelled values as wedges of a circle, each a share of the whole. Each slice takes its color from a scheme resolved off the live theme (skittles by default, so the parts read as distinct), or pass explicit colors and reverse.

Set variant="donut" for a ring with the total in its center. It's interactive: hovering or focusing a slice dims the rest and floats its value and share, and the chart is mirrored into a visually-hidden table so assistive tech reads the numbers. A legend names each slice; optional showValues prints the percentage on each wedge. Size it with size; zero and negative values drop out, and a chart with nothing left to plot shows a muted No data message in place of the wedges.

When to use

How this component composes with the rest of the set.

Colors come from the theme register, so the slices match the surrounding UI. skittles (the default) keeps the parts distinct; statuses pins each slice to a semantic tone (success, failed, warn, info, skipped, live) for discrete-outcome charts, distinct from the sequential status severity ramp; pass an explicit array to pin brand colors, and a var(--token) string in that array lands straight in the fill and resolves against the theme.
Under statuses, give each slice an explicit tone when a category can be absent: without one, colors are assigned by position, so a run where nothing failed drops the failed slice and shifts every survivor to the wrong tone. A tone pins each slice to its meaning regardless of which categories are present.
Reach for a donut when you want a headline total in the middle; a full pie when the parts are the whole story.
Pair with a Stat or a Bar in the Metrics family for a composition-plus-trend view.

Props

8 props, straight from the manifest.

PropTypeDefaultBindingsDescription
data { label: string; value: number; tone?: StatusTone }[]
html svelte astro
The slices: a label and a value each. JS property in html/svelte, JSON attribute or prop in astro. Zero and negative values drop out. Under `scheme="statuses"`, an optional `tone` (`success` / `failed` / `warn` / `info` / `skipped` / `live`) colors a slice by meaning, so a dropped zero-value category never shifts the rest.
variant "pie" | "donut"
pie donut
pie
html svelte astro
A full pie, or a `donut` ring with the total in its center.
scheme SeriesScheme | string[]
accents skittles statuses thermal status
skittles
html svelte astro
How slices are colored: a built-in scheme resolved off the theme, or an explicit color array.
reverse boolean false
html svelte astro
Flips the scheme end for end.
showValues boolean false
html svelte astro
Prints each slice's percentage on the wedge (slices under 5% are skipped for legibility). Kebab `show-values`.
legend boolean true
html svelte astro
Shows the slice legend; set false to hide it.
size number 200
html svelte astro
The chart diameter in pixels.
label string
html svelte astro
An accessible name for the chart, used as the data table's caption.

Appearance

Variants

pie

.xtyle-pie

A full pie of solid wedges.

donut

.xtyle-pie--donut

A ring with the total in its center.

States

slice-hover

.xtyle-pie--hovering .xtyle-pie__slice:not(.is-active)

Pointer over or keyboard focus on a slice: the rest dim and a value/share readout floats above it.

slice-focus

.xtyle-pie__slice:focus-visible

Keyboard focus on a slice draws a token ring; each slice is a tab stop announcing its label, value, and share.

Anatomy

The named parts that make up the component, with their selectors.

chart

.xtyle-pie

The <figure> root holding the SVG, legend, tooltip, and the accessible data table.

--font-sans

slice

.xtyle-pie__slice

One wedge, filled with its palette color and separated by a hairline; the focus/hover target.

--bg-1 --ring --border-thick --duration-fast --ease-standard

center

.xtyle-pie__center

The donut's center total.

--fg-0 --text-lg --weight-bold

legend

.xtyle-pie__legend

The slice key; each item pairs a color dot with the slice label.

--fg-1 --text-sm --space-1 --space-3 --radius-sm

tooltip

.xtyle-pie__tooltip

The floating value/share readout shown on hover or focus of a slice.

--surface-overlay --surface-overlay-border --elevation-3 --radius-md --fg-0

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 25/25 consumed tokens produced default register: 299 tokens

Live coverage check against the xtyle-default register (derive(xtyleDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--bg-0 --bg-1 --border-thick --border-thin --duration-fast --ease-standard --elevation-3 --fg-0 --fg-1 --fg-2 --font-sans --leading-normal --radius-md --radius-sm --ring --space-1 --space-2 --space-3 --surface-overlay --surface-overlay-border --text-lg --text-sm --text-xs --weight-bold --weight-semibold

Accessibility

Each slice carries role="img" and an aria-label naming its label, value, and share, and is a focusable tab stop, so the chart is navigable by keyboard.
The full breakdown is mirrored into a visually-hidden <table> (label, value, share), and the legend names every slice in text, so meaning never rides on color alone.

Code

Pie

Four sources as shares of the whole, colored from the skittles scheme.

<xtyle-pie label="Traffic by source"></xtyle-pie>
<script>
	document.querySelector("xtyle-pie").data = [
		{ label: "Direct", value: 42 },
		{ label: "Search", value: 30 },
		{ label: "Social", value: 18 },
		{ label: "Referral", value: 10 },
	];
</script>
<script lang="ts">
	import { Pie } from "@xtyle/svelte";

	const data = [
		{ label: "Direct", value: 42 },
		{ label: "Search", value: 30 },
		{ label: "Social", value: 18 },
		{ label: "Referral", value: 10 },
	];
</script>

<Pie {data} label="Traffic by source" />
---
import { Pie } from "@xtyle/astro";
const data = [
	{ label: "Direct", value: 42 },
	{ label: "Search", value: 30 },
	{ label: "Social", value: 18 },
	{ label: "Referral", value: 10 },
];
---

<Pie data={data} label="Traffic by source" />

Donut

variant="donut" opens the center for the total; here on the accents scheme.

<xtyle-pie variant="donut" scheme="accents" label="Budget"></xtyle-pie>
<script>
	document.querySelector("xtyle-pie").data = [
		{ label: "Rent", value: 1200 },
		{ label: "Food", value: 600 },
		{ label: "Transit", value: 300 },
		{ label: "Fun", value: 400 },
	];
</script>
<script lang="ts">
	import { Pie } from "@xtyle/svelte";

	const data = [
		{ label: "Rent", value: 1200 },
		{ label: "Food", value: 600 },
		{ label: "Transit", value: 300 },
		{ label: "Fun", value: 400 },
	];
</script>

<Pie {data} variant="donut" scheme="accents" label="Budget" />
---
import { Pie } from "@xtyle/astro";
const data = [
	{ label: "Rent", value: 1200 },
	{ label: "Food", value: 600 },
	{ label: "Transit", value: 300 },
	{ label: "Fun", value: 400 },
];
---

<Pie data={data} variant="donut" scheme="accents" label="Budget" />

Discrete outcomes

scheme="statuses" colors each slice by a semantic tone (success, failed, warn, info, skipped, live) so a run-outcome chart reads by meaning, and stays right even when a category is absent.

<xtyle-pie variant="donut" scheme="statuses" label="Runs"></xtyle-pie>
<script>
	// Give each slice a semantic `tone` so it colors by meaning: a run where nothing
	// failed drops the failed slice without shifting the others' colors.
	document.querySelector("xtyle-pie").data = [
		{ label: "Passed", value: 128, tone: "success" },
		{ label: "Failed", value: 14, tone: "failed" },
		{ label: "Flaky", value: 9, tone: "warn" },
		{ label: "Skipped", value: 21, tone: "skipped" },
		{ label: "Running", value: 6, tone: "live" },
		{ label: "Queued", value: 11, tone: "info" },
	];
</script>
<script lang="ts">
	import { Pie } from "@xtyle/svelte";

	// A semantic `tone` per slice colors by meaning, stable even if a category is absent.
	const data = [
		{ label: "Passed", value: 128, tone: "success" },
		{ label: "Failed", value: 14, tone: "failed" },
		{ label: "Flaky", value: 9, tone: "warn" },
		{ label: "Skipped", value: 21, tone: "skipped" },
		{ label: "Running", value: 6, tone: "live" },
		{ label: "Queued", value: 11, tone: "info" },
	];
</script>

<Pie {data} variant="donut" scheme="statuses" label="Runs" />
---
import { Pie } from "@xtyle/astro";
// A semantic `tone` per slice colors by meaning, stable even if a category is absent.
const data = [
	{ label: "Passed", value: 128, tone: "success" },
	{ label: "Failed", value: 14, tone: "failed" },
	{ label: "Flaky", value: 9, tone: "warn" },
	{ label: "Skipped", value: 21, tone: "skipped" },
	{ label: "Running", value: 6, tone: "live" },
	{ label: "Queued", value: 11, tone: "info" },
];
---

<Pie data={data} variant="donut" scheme="statuses" label="Runs" />