Skip to content
misoto22 design

Charts

WaterfallChart

How a total got from one figure to another.

When to reach for it

“Why did this change”, where the contributions can be negative. A pie cannot hold a negative slice; a BarChart is right when the parts need not add up to the gap between two totals.

Examples

default

ARR bridge, FY24 to FY25Thousands of AUD. The steps are simultaneous; the order is editorial.
ARR bridge, FY24 to FY25
nameChangeRunning total
FY24 ARR4,2004,200
New business1,1805,380
Expansion6406,020
Downgrades-3105,710
Churn-8204,890
FY25 ARR04,890

subtotals

Operating profit bridge
Operating profit bridge
nameChangeRunning total
Revenue8,4008,400
COGS-3,1005,300
Gross profit05,300
Sales-1,4503,850
R&D-1,9001,950
G&A-7201,230
Operating profit01,230

Notes

How a total got from one figure to another — an opening balance, the signed contributions that moved it, and where it closed.

The form for "why did this change", which a pair of bars cannot answer and a pie chart answers wrongly, because contributions can be NEGATIVE and a slice cannot. Reach for <BarChart> when the parts do not have to add up to the gap between two totals, and for <FunnelChart> when the quantity only ever shrinks.

The connectors are the claim to be careful about. They draw the steps as a sequence — this happened, then this — and most breakdowns are not sequential at all: churn and expansion in the same month are simultaneous, and the order they are listed in is an editorial choice. The arithmetic survives any order; the STORY does not, and a reader will take the leftmost bar as the first cause. Two related traps: the intermediate bars are floating lengths read against no baseline, so a small step high up the cascade is hard to compare with a large one near zero; and any step that is itself a net of two larger opposing movements is invisible as such. Where the order is arbitrary, say so in the description.

Recharts earns its place for the axes, grid and tooltip. Each bar is a floating range — from the running total to the new one — with a custom shape over it, because Recharts has no waterfall mark and the connectors have to be drawn from the same geometry as the bars they join.

Props

WaterfallChart props
PropTypeDefaultDescription
childrenrequiredReactNodeThe composed parts — axes, grid, tooltip, and `<WaterfallChart.Bars>`.
datarequiredWaterfallStep[]The steps, in the order they are applied. Order is the arithmetic: the chart does not sort, because a different order is a different total at every intermediate bar.
titlerequiredstringWhat the chart shows, in a sentence a reader could act on. Required, and announced to a screen reader even when it is not printed.
chartPropsComponentProps<typeof RechartsBarChart>Escape hatch onto the raw Recharts chart element.
classNamestringMerged onto the figure, last, so a call site can size or space it.
configChartConfigDEFAULT_CONFIGThe single series — its label and its paint. Only the FIRST entry is read; a waterfall has one quantity and as many bars as it has steps.
descriptionReactNodeA line under the title — the unit, the window, the caveat.
emptyChartEmptyProps | falseWhat the chart shows when it has nothing to draw. `false` keeps the axes, for a chart whose emptiness is itself the reading.
formatValue(value: number) => stringdefaultTickFormats every number the chart prints — ticks, labels, tooltip, table.
hideDataTablebooleanfalseDrops the hidden table view. Only correct when the page prints the data itself.
showTitlebooleanPrints the title above the plot instead of hiding it from sight.

Types

TSX
export type WaterfallStepType = 'delta' | 'total'
export type WaterfallDirection = 'increase' | 'decrease' | 'total'

Accessibility

  • The connectors draw the steps as a sequence, and most breakdowns are not sequential — churn and expansion in the same month are simultaneous, and a reader takes the leftmost bar as the first cause. Where the order is arbitrary, say so in description.
  • Intermediate bars are floating lengths read against no baseline, so a small step high up the cascade is hard to compare with a large one near zero. Total bars sit on the axis and are the only ones a reader can read absolutely.
  • Direction is carried by the label’s sign and the bar’s texture as well as its position, so the reading survives greyscale and forced colours.
  • A closing bar with no value is computed from the deltas, which keeps the arithmetic in the data rather than in the caller’s head.