Installation
Theme
Mode

Data viz

Cumulative flow

A stacked area of how many items sit in each status over time — the CFD. The width of each colored band is the work-in-progress at that stage, so a widening band reveals a bottleneck and a steepening Done edge shows throughput. Hover any day for the breakdown. Built on the shared Orbit chart scaffolding.

$npx shadcn@latest add @orbit/cumulative-flow-chart

Overview

Switch the range, hover a day for the per-status counts, or hover a legend entry to isolate its band.

Cumulative flow — stacked status bands with range toggle
Cumulative flow
Items in each status over the last 30 days

Reading it

The vertical thickness of a band at any day is the count in that status. Read the shapes, not just the lines.

Throughput
The slope of the top of the Done band is delivery rate. Steeper means more items finished per day.
WIP = band height
A band’s vertical thickness is how many items sit in that status. A fat In-progress band is too much in flight.
Bottlenecks
A band that keeps widening while the ones below it stay thin is a stage where work piles up faster than it clears.
Cycle time
The horizontal gap between when work enters the top and exits the bottom approximates how long an item takes.

Controlled

Hide the built-in range toggle with showRangeToggle={false} and drive the window from outside via range + onRangeChange.

range + onRangeChange · showRangeToggle={false}
Controlled from outside · range=14
Cumulative flow
Items in each status over the last 14 days

Custom bands

Bands are entities: pass your own workflow (bottom band first) and each status keeps its color everywhere it appears. Fold long tails before charting — five or six bands stay legible.

bands — a three-stage workflow, statuses pre-folded in the data
Cumulative flow
Three-stage workflow over the last 30 days

Props

PropTypeDefaultDescription
dataRecord<string, number>[]Daily counts keyed by band key, oldest first. The active range shows the last N days.
bands{ key: string; label: string; color: string }[]CUMULATIVE_FLOW_BANDSStacking order, bottom band first. Defaults to Done / In review / In progress / Todo / Backlog with tokenized status colors.
rangesnumber[][14, 30, 60]Day counts offered by the range toggle.
rangenumberControlled range (days shown). Pair with onRangeChange.
defaultRangenumber30Uncontrolled initial range.
onRangeChange(range) => voidFires when the range toggle (or a controlled parent) changes the window.
titlestring"Cumulative flow"Card heading.
subtitlestringOverrides the “Items in each status over the last N days” subtitle.
heightnumber300Plot height in px. Width is responsive.
showRangeTogglebooleantrueRange toggle in the header.
showLegendbooleantrueBordered legend row with the latest counts; hover / focus isolates a band.
formatDay(index: number) => stringAxis and tooltip day label. Defaults to “D5” on the axis, “Day 5” in the tooltip.
ariaLabelstringPlain-language summary for the chart's role=“img”.
…restHTMLAttributes<HTMLDivElement>Forwarded to the root card, including ref and className.

Usage

Use a CFD to watch flow and WIP across statuses over time. For a single sprint's completion use Burndown; for the current snapshot use the Kanban board itself.

Do

Order bands by workflow

Stack statuses in pipeline order — Done at the bottom, Backlog at the top — so the chart reads like the board flows.

Don’t

Use too many statuses

Five or six bands stay legible. A dozen thin slivers turn the CFD into stripes nobody can read.

Do

Keep colors consistent

Use the same status colors as the board and list, so Done is always green here and everywhere else.

Don’t

Reset the cumulative total

A CFD is cumulative — bands only grow as scope is added. Don’t subtract finished work or the shapes lie.

Keyboard & accessibility

The chart renders as a labelled image; the crosshair tooltip reads every band at the hovered day, and legend entries are keyboard-focusable.

roleimg with an aria-label naming the statuses and span
TooltipEvery band's count at the hovered day, on a crosshair
LegendFocusable entries name each band and isolate it on hover / focus
ContrastStatus colors are tokens, validated on both modes