Waterfall chart
Updated
WaterfallChart floats one bar per row from the running total, solid when it rises and striped when it falls, with a total at half tone and dashed connectors between the bars. Like every DitherCharts chart, it fills its container's width, animates in, moves a cursor with the arrow keys, and keeps a data table for screen readers.
Example
Waterfall
Monthly cash flow, rises solid and falls striped, with an end total
| month | Cash | Running |
|---|---|---|
| Jan | +120 | 120 |
| Feb | +80 | 200 |
| Mar | -60 | 140 |
| Apr | +140 | 280 |
| May | -30 | 250 |
| Jun | +90 | 340 |
| Jul | -110 | 230 |
| Aug | +60 | 290 |
| Total | - | 290 |
import { WaterfallChart } from "@/components/dithercharts/waterfall-chart"
import type { ChartConfig } from "@/components/dithercharts/chart-config"
const chartData = [
{ month: "Jan", cash: 120 },
{ month: "Feb", cash: 80 },
{ month: "Mar", cash: -60 },
{ month: "Apr", cash: 140 },
{ month: "May", cash: -30 },
{ month: "Jun", cash: 90 },
{ month: "Jul", cash: -110 },
{ month: "Aug", cash: 60 },
]
const chartConfig = {
cash: { label: "Cash" },
} satisfies ChartConfig
export function ChartWaterfall() {
return (
<WaterfallChart
data={chartData}
config={chartConfig}
xKey="month"
dataKey="cash"
label="Cash flow"
/>
)
}
Install
Charts install with DitherCharts Pro. See Installation to log in and import the stylesheet.
npx dithercharts add waterfall-chart
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| datarequired | Type readonly ChartRow[] | Default – | One row per change, left to right, e.g. { month: "Jan", cash: 120 }; a missing change counts as 0. |
| configrequired | Type ChartConfig | Default – | An entry for dataKey: the change's label. |
| xKeyrequired | Type string | Default – | The row key that holds the x label, e.g. "month". |
| dataKeyrequired | Type string | Default – | The row key that holds each change, e.g. "cash". |
| totalKey | Type string | Default – | The row key that marks a subtotal (any value but 0, "" or none): its bar runs from 0 to the running total, its own value ignored. |
| total | Type boolean | Default true | A final bar from 0 to the running total. |
| totalLabel | Type string | Default "Total" | The final bar's x label. |
| labelrequired | Type string | Default – | Accessible name, e.g. "Cash flow". Also captions the table twin. |
| connectors | Type boolean | Default true | A dashed line from each bar's end to the next bar's start. |
| valueLabels | Type boolean | Default true | Each change, signed, past its bar's end, and each total over its bar. |
| yAxis | Type boolean | Default false | Value labels beside the grid lines. |
| tooltip | Type TooltipOptions | Default – | The tooltip's label, and the bar it opens on at rest. |
| style | Type StyleId | Default "bayer4" | Dither style. |
| animation | Type "develop" | "none" | Default "develop" | Entrance animation; reduced motion always shows the final frame. |
| height | Type number | Default 300 | Height in CSS pixels; the width fills the container. |
| cell | Type number | Default 3 | Dither cell size in CSS pixels. |
| className | Type string | Default – | Classes on the chart's outer figure. |
Styles
The dither styles style takes:
"bayer2""bayer4""bayer8""blue-noise""halftone""crosshatch""pixel""stipple""engraved""mezzotint""woodcut""floyd-steinberg""atkinson""riemersma"
Keyboard and accessibility
The chart is one Tab stop. Focusing it from the keyboard puts the cursor on the first bar, or where the keys last left it; moving focus away clears it. The keys stop at the ends.
| Key | Action |
|---|---|
| Left arrow Right arrow | Previous / next bar |
| Home End | First / last bar |
| Escape | Dismiss the cursor |
Screen readers
- The chart's label names it, says how many bars it has and lists these keys.
- Each key press is announced in a polite live region. Moving the pointer is silent.
- The
tablebutton under the chart shows its data as a table. Screen readers can reach the table even while it's hidden; clicking a row moves the cursor there and announces it. - With
legend, each entry is a toggle button. The last one showing can't be hidden, but its button stays focusable.
On a touch screen, a tap pins the cursor and a tap outside the chart dismisses it.

