Components / Charts
Streamgraph
Layered streams on a wiggle baseline that morph between ranges, with a layer you can isolate and read week by week.
Install
npx shadcn@latest add https://irisui.dev/r/streamgraph.jsonimport { Streamgraph } from "@/components/iris/streamgraph/streamgraph";Preview
Streamgraph
Layered streams on a wiggle baseline that show how a mix of parts changes over time, with layers you can isolate and read week by week.
When to use
- How the composition of a total shifts over many periods, when the overall rhythm matters more than exact values: tickets by topic, usage by feature, traffic by source.
- Spotting when a new part arrives or swells, such as a launch wave.
- Not when exact comparisons matter; use
LineChart. For a few periods or categories, useBarChart. Avoid it for negative values.
Usage
import { Streamgraph } from "@/components/iris/streamgraph/streamgraph";
const series = [
{ key: "en", label: "English" },
{ key: "it", label: "Italian" },
{ key: "el", label: "Greek" },
];
const data = [
{ key: "2026-10-05", label: "Week of 5 Oct", axisLabel: "Oct", values: { en: 124, it: 112, el: 88 } },
{ key: "2026-10-12", label: "Week of 12 Oct", values: { en: 131, it: 108, el: 94 } },
{ key: "2026-10-19", label: "Week of 19 Oct", values: { en: 119, it: 116, el: 91 } },
];
h(Streamgraph, { data, series, label: "Stories by language", unit: "stories", categoryLabel: "Week" });
Props
| Prop | Type | Default | Description |
|---|---|---|---|
data |
{ key; label; axisLabel?; values: Record<string, number> }[] |
required | Points in time. Missing values count as zero; negatives as zero. Datasets of different lengths morph into each other. |
series |
{ key; label; color? }[] |
required | Layers from the centre out: the first runs through the middle, the rest alternate above and below. Put the most important layer first. |
label |
string |
required | Names the chart for assistive technology. |
unit |
string |
"" |
Unit after each value. |
height |
number |
260 |
Plot height; width follows the container. |
offset |
"wiggle" | "silhouette" | "zero" |
"wiggle" |
Baseline: wiggle minimises slopes, silhouette centres the stack, zero stacks from a flat baseline (use when totals matter). |
formatValue |
(value, series) => string |
— | Tooltip and table values. |
hiddenSeries / defaultHiddenSeries / onHiddenSeriesChange |
string[] / callback |
— | Hidden layers; a hidden layer thins to nothing and the rest reflow. |
onActiveChange |
(index, seriesKey) => void |
— | Fires as the reading moves; nulls when it leaves. |
legend |
boolean |
true |
Layer toggles above the plot; hover or focus previews a layer. |
directLabels |
boolean |
true |
Names each layer at its widest stretch when the text fits. |
categoryLabel / emptyLabel |
string |
"Date" / "No data for this range" | Hidden table header; empty state. |
className |
string |
— | Class on the root figure. |
ref |
Ref<HTMLElement> |
— | Forwarded to the root figure. |
Notes
- Keyboard: Tab focuses the plot on the latest point. Left/Right move through time, Up/Down move the isolated layer through the stack, Page Up/Down and Home/End jump, Escape clears.
- Accessibility: the plot is a focusable group; each reading announces the point, the isolated layer's value and the total. Legend toggles use
aria-pressed; a hidden table lists every value. Layers are separated by a 2px--surfacegap and named in place, so identity does not rest on shade alone. - Colours come from
--series-1…4(first in the accent), then neutral steps. Keep to about eight layers and fold the rest into Other. - Motion: layers morph between datasets; reduced motion swaps them without animation.