Streamgraph
Layered streams on a wiggle baseline that morph between ranges, with a layer you can isolate and read week by week.
pnpm dlx shadcn@latest add @uiarc/streamgraphSupport tickets by topic
Support tickets by topic, Week of Sep 22, 2025 to Week of Sep 14, 2026. Bugs, latest 108 tickets. Billing, latest 78 tickets. Integrations, latest 96 tickets. Onboarding, latest 63 tickets. Account access, latest 43 tickets. Feature requests, latest 82 tickets.
| Week | Bugs | Billing | Integrations | Onboarding | Account access | Feature requests |
|---|---|---|---|---|---|---|
| Week of Sep 22, 2025 | 110 tickets | 78 tickets | 35 tickets | 55 tickets | 53 tickets | 61 tickets |
| Week of Sep 29, 2025 | 130 tickets | 80 tickets | 37 tickets | 56 tickets | 49 tickets | 62 tickets |
| Week of Oct 6, 2025 | 136 tickets | 70 tickets | 33 tickets | 63 tickets | 48 tickets | 61 tickets |
| Week of Oct 13, 2025 | 130 tickets | 79 tickets | 35 tickets | 61 tickets | 49 tickets | 59 tickets |
| Week of Oct 20, 2025 | 125 tickets | 71 tickets | 39 tickets | 58 tickets | 45 tickets | 63 tickets |
| Week of Oct 27, 2025 | 151 tickets | 68 tickets | 38 tickets | 70 tickets | 40 tickets | 61 tickets |
| Week of Nov 3, 2025 | 141 tickets | 74 tickets | 42 tickets | 69 tickets | 40 tickets | 58 tickets |
| Week of Nov 10, 2025 | 129 tickets | 74 tickets | 38 tickets | 66 tickets | 42 tickets | 57 tickets |
| Week of Nov 17, 2025 | 137 tickets | 73 tickets | 46 tickets | 70 tickets | 38 tickets | 57 tickets |
| Week of Nov 24, 2025 | 140 tickets | 77 tickets | 47 tickets | 72 tickets | 34 tickets | 60 tickets |
| Week of Dec 1, 2025 | 139 tickets | 79 tickets | 41 tickets | 65 tickets | 37 tickets | 57 tickets |
| Week of Dec 8, 2025 | 138 tickets | 79 tickets | 45 tickets | 75 tickets | 40 tickets | 64 tickets |
| Week of Dec 15, 2025 | 107 tickets | 72 tickets | 48 tickets | 70 tickets | 33 tickets | 57 tickets |
| Week of Dec 22, 2025 | 75 tickets | 51 tickets | 34 tickets | 55 tickets | 26 tickets | 40 tickets |
| Week of Dec 29, 2025 | 71 tickets | 52 tickets | 30 tickets | 73 tickets | 27 tickets | 38 tickets |
| Week of Jan 5, 2026 | 99 tickets | 67 tickets | 49 tickets | 136 tickets | 42 tickets | 48 tickets |
| Week of Jan 12, 2026 | 111 tickets | 69 tickets | 52 tickets | 174 tickets | 49 tickets | 52 tickets |
| Week of Jan 19, 2026 | 106 tickets | 68 tickets | 56 tickets | 159 tickets | 49 tickets | 52 tickets |
| Week of Jan 26, 2026 | 104 tickets | 78 tickets | 53 tickets | 144 tickets | 56 tickets | 52 tickets |
| Week of Feb 2, 2026 | 102 tickets | 79 tickets | 53 tickets | 88 tickets | 49 tickets | 46 tickets |
| Week of Feb 9, 2026 | 101 tickets | 72 tickets | 56 tickets | 59 tickets | 55 tickets | 46 tickets |
| Week of Feb 16, 2026 | 96 tickets | 71 tickets | 56 tickets | 48 tickets | 49 tickets | 45 tickets |
| Week of Feb 23, 2026 | 95 tickets | 72 tickets | 60 tickets | 43 tickets | 44 tickets | 45 tickets |
| Week of Mar 2, 2026 | 97 tickets | 76 tickets | 58 tickets | 38 tickets | 42 tickets | 44 tickets |
| Week of Mar 9, 2026 | 104 tickets | 77 tickets | 60 tickets | 37 tickets | 43 tickets | 50 tickets |
| Week of Mar 16, 2026 | 103 tickets | 81 tickets | 60 tickets | 39 tickets | 40 tickets | 44 tickets |
| Week of Mar 23, 2026 | 120 tickets | 87 tickets | 66 tickets | 35 tickets | 37 tickets | 46 tickets |
| Week of Mar 30, 2026 | 122 tickets | 146 tickets | 65 tickets | 36 tickets | 40 tickets | 51 tickets |
| Week of Apr 6, 2026 | 124 tickets | 203 tickets | 68 tickets | 34 tickets | 37 tickets | 50 tickets |
| Week of Apr 13, 2026 | 141 tickets | 198 tickets | 66 tickets | 35 tickets | 39 tickets | 51 tickets |
| Week of Apr 20, 2026 | 128 tickets | 119 tickets | 63 tickets | 36 tickets | 35 tickets | 47 tickets |
| Week of Apr 27, 2026 | 139 tickets | 81 tickets | 72 tickets | 38 tickets | 40 tickets | 47 tickets |
| Week of May 4, 2026 | 139 tickets | 80 tickets | 68 tickets | 35 tickets | 39 tickets | 54 tickets |
| Week of May 11, 2026 | 136 tickets | 74 tickets | 70 tickets | 36 tickets | 43 tickets | 52 tickets |
| Week of May 18, 2026 | 139 tickets | 77 tickets | 73 tickets | 42 tickets | 47 tickets | 52 tickets |
| Week of May 25, 2026 | 131 tickets | 79 tickets | 68 tickets | 47 tickets | 51 tickets | 56 tickets |
| Week of Jun 1, 2026 | 125 tickets | 70 tickets | 78 tickets | 48 tickets | 47 tickets | 57 tickets |
| Week of Jun 8, 2026 | 133 tickets | 74 tickets | 84 tickets | 50 tickets | 53 tickets | 63 tickets |
| Week of Jun 15, 2026 | 165 tickets | 85 tickets | 145 tickets | 54 tickets | 53 tickets | 67 tickets |
| Week of Jun 22, 2026 | 199 tickets | 102 tickets | 147 tickets | 60 tickets | 50 tickets | 69 tickets |
| Week of Jun 29, 2026 | 156 tickets | 93 tickets | 136 tickets | 55 tickets | 48 tickets | 70 tickets |
| Week of Jul 6, 2026 | 114 tickets | 109 tickets | 103 tickets | 62 tickets | 50 tickets | 65 tickets |
| Week of Jul 13, 2026 | 110 tickets | 100 tickets | 81 tickets | 68 tickets | 44 tickets | 73 tickets |
| Week of Jul 20, 2026 | 103 tickets | 89 tickets | 79 tickets | 65 tickets | 40 tickets | 73 tickets |
| Week of Jul 27, 2026 | 100 tickets | 78 tickets | 83 tickets | 70 tickets | 38 tickets | 81 tickets |
| Week of Aug 3, 2026 | 102 tickets | 85 tickets | 90 tickets | 69 tickets | 41 tickets | 72 tickets |
| Week of Aug 10, 2026 | 88 tickets | 74 tickets | 84 tickets | 73 tickets | 37 tickets | 79 tickets |
| Week of Aug 17, 2026 | 102 tickets | 77 tickets | 93 tickets | 67 tickets | 35 tickets | 84 tickets |
| Week of Aug 24, 2026 | 105 tickets | 77 tickets | 82 tickets | 66 tickets | 33 tickets | 74 tickets |
| Week of Aug 31, 2026 | 93 tickets | 80 tickets | 87 tickets | 74 tickets | 36 tickets | 80 tickets |
| Week of Sep 7, 2026 | 100 tickets | 72 tickets | 96 tickets | 64 tickets | 40 tickets | 85 tickets |
| Week of Sep 14, 2026 | 108 tickets | 78 tickets | 96 tickets | 63 tickets | 43 tickets | 82 tickets |
- Showing the changing share of topics, channels, or genres week by week.
- Storytelling dashboards where the shape of seasonality and spikes is the point.
- Comparing ranges where a morph between them explains what changed.
- Use line-chart when exact values or comparisons between series matter.
- Use bar-chart for a few periods or categories.
- Avoid it for data with negative values; streams stack magnitudes.
Installation
Add Streamgraph with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/streamgraphAdds the component and its local dependencies, and installs motion. First time? Add the @uiarc registry to components.json, or use the full URL:
import { Streamgraph } from "@/registry/components/streamgraph/streamgraph"; const series = [{ key: "bugs", label: "Bugs" }, { key: "billing", label: "Billing" }, { key: "onboarding", label: "Onboarding" }];const data = weeks.map(week => ({ key: week.iso, label: `Week of ${week.name}`, axisLabel: week.monthStart ? week.month : undefined, values: week.tickets })); export function TicketsByTopic() { return <Streamgraph data={data} series={series} label="Support tickets by topic" unit="tickets" categoryLabel="Week" />;}Streamgraph
Layers stacked on a wiggle baseline that flow over time. Switching ranges morphs every layer; hovering one isolates it and reads every layer at that point.
dataRequired{ key: string; label: string; axisLabel?: string; values: Record<string, number | undefined> }[]–Points in time. Datasets of any length morph into each other.seriesRequired{ key: string; label: string; color?: string }[]–Layers from the centre out: the first runs through the middle and the rest alternate above and below it.labelRequiredstring–Names the chart for assistive technology.unitstring""Unit after each value.heightnumber260Plot height in pixels.offset"wiggle" | "silhouette" | "zero""wiggle"Wiggle minimises layer slopes, silhouette centres the stack, zero stacks from a flat baseline.formatValue(value: number, series) => string–Formats values in the tooltip and table.hiddenSeriesstring[]–Controlled hidden layers. A hidden layer thins to nothing and the rest reflow.defaultHiddenSeriesstring[]–Initial hidden layers when uncontrolled.onHiddenSeriesChange(hidden: string[]) => void–Called when a legend toggle is pressed.onActiveChange(index: number | null, seriesKey: string | null) => void–Called as the reading moves between points and layers.legendbooleantrueLayer toggles above the plot.directLabelsbooleantrueNames each layer at its thickest stretch when the text fits.categoryLabelstring"Date"Header of the first column in the screen reader table.emptyLabelstring"No data for this range"Shown when there are no points.classNamestring–Extra class on the figure.- Tab
- Focuses the plot and reads the latest point.
- ArrowLeftorArrowRight
- Moves through time.
- ArrowUporArrowDown
- Moves the isolated layer up or down the stack.
- PageUporPageDownorHomeorEnd
- Jumps by a sixth of the range, or to the first or last point.
- Escape
- Clears the reading.
- The plot is a focusable group; each reading is announced with the point, the isolated layer's value, and the total.
- Legend toggles are buttons with aria-pressed; hovering or focusing one isolates its layer.
- A visually hidden table lists every point and layer value.
- Layers are separated by a 2px surface gap and named in place, so identity never rests on shade alone.
- The stream swells out of a hairline along its centre the first time it is seen.
- New data blends every layer on a shared grid, so ranges of different lengths morph without redrawing.
- Hidden layers thin to nothing while the rest reflow; the crosshair and tooltip glide on springs.
- Reduced motion jumps to the final shapes and keeps the crosshair and tooltip without travel.
- The plot fills its container; axis labels thin out to one per 72px, counted back from the latest.
- Direct labels hide where a layer is too thin or the plot too narrow; the tooltip and legend still name it.
- Touch drags scrub through time with pointer capture while vertical page scroll stays free.
- Each layer is resampled once per data change onto 161 points; paint recomputes the baseline and writes paths directly.
- Hover state re-renders only the tooltip and a few attributes; morphs never re-render React per frame.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Choose it for how a mix changes over time when the overall rhythm matters more than exact totals.
- Put the most important layer first; it runs through the middle of the stream.
- Use offset="zero" when people need to read totals against a baseline, like a stacked area chart.
- Keep layers to about eight; fold the rest into Other.
The full library index for assistants is at /llms.txt.