Skip to content

Waterfall Chart

ChartsSince 0.4.0
import { WaterfallChart } from '@absoluteui/components/waterfall-chart';
import '@absoluteui/components/waterfall-chart/style.css';

Using Angular? See Waterfall Chart for Angular.

An accessible SVG waterfall chart that shows how a starting value changes through a sequence of increases and decreases. It provides:

  • delta steps that float from the running total, total steps that drop to the baseline (an opening balance, a subtotal, or the closing total);
  • dashed connectors between consecutive steps and signed value labels;
  • keyboard-reachable steps (one tab stop), including steps without a value, with a tooltip on focus and hover;
  • a legend of the step kinds present (Increase, Decrease, Total);
  • a generated accessible summary (start, end, largest increase and decrease) and a data table fallback (change, running total, type);
  • kinds that differ by color, texture, signed labels, and accessible names, never by color alone (WCAG 1.4.1).
  • Bridges from an opening to a closing value (profit and loss, cash flow, headcount changes).
  • Explaining which steps contributed most to a change.
  • Independent values per category: use Bar Chart.
  • Trends over time: use Line Chart.
  • Part-to-whole without an order: use Pie Chart.

Profit bridge with an opening total, deltas, and a closing total

Section titled “Profit bridge with an opening total, deltas, and a closing total”
import { WaterfallChart, type WaterfallStep } from '@absoluteui/components/waterfall-chart';
const steps: WaterfallStep[] = [
{ id: 'open', label: 'Opening', kind: 'total', value: 100 },
{ id: 'sales', label: 'Sales', value: 40 },
{ id: 'refunds', label: 'Refunds', value: -15 },
{ id: 'other', label: 'Other', value: null },
{ id: 'close', label: 'Closing', kind: 'total' },
];
const host = document.createElement('div');
document.body.append(host);
WaterfallChart.create(host, {
label: 'Profit bridge',
steps,
valueFormat: { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 },
valueAxis: { label: 'EUR' },
});
import { WaterfallChart } from '@absoluteui/components/waterfall-chart';
const host = document.querySelector<HTMLElement>('#headcount');
if (host) {
const chart = WaterfallChart.create(host, {
label: 'Headcount',
steps: [
{ id: 'start', label: 'Start', kind: 'total', value: 250 },
{ id: 'hires', label: 'Hires', value: 30 },
{ id: 'leavers', label: 'Leavers', value: -12 },
{ id: 'end', label: 'End', kind: 'total' },
],
colors: { increase: 5, decrease: 6, total: 1 },
connectors: false,
});
host.dataset.summary = chart.summary;
}
import { WaterfallChart } from '@absoluteui/components/waterfall-chart';
import '@absoluteui/components/waterfall-chart/style.css';
const host = document.querySelector<HTMLElement>('#cash');
if (host) {
WaterfallChart.create(host, {
label: 'Cash flow',
steps: [
{ id: 'start', label: 'Start', kind: 'total', value: 500 },
{ id: 'in', label: 'Receipts', value: 320 },
{ id: 'out', label: 'Payments', value: -410 },
{ id: 'end', label: 'End', kind: 'total' },
],
valueFormat: { style: 'currency', currency: 'USD', maximumFractionDigits: 0 },
});
}
import { WaterfallChart, type WaterfallStep } from '@absoluteui/components/waterfall-chart';
const steps: WaterfallStep[] = [
{ id: 'open', label: 'Opening', kind: 'total', value: 100 },
{ id: 'sales', label: 'Sales', value: 40 },
{ id: 'refunds', label: 'Refunds', value: -15 },
{ id: 'close', label: 'Closing', kind: 'total' },
];
const host = document.createElement('div');
document.body.append(host);
WaterfallChart.create(host, { label: 'Profit bridge', steps });

Export: @absoluteui/components/chart-export (chartToSvg, chartToPng, downloadChart) exports any chart instance to SVG or PNG.

<div class="aui-chart aui-waterfall-chart [aui-chart--patterns]">
<div class="aui-chart__header">
<div class="aui-chart__title" id="T">title</div>
<p class="aui-chart__description" id="D">description</p>
<div class="aui-chart__toolbar" hidden/>
</div>
<ul class="aui-chart__legend" aria-label="Legend">
<li class="aui-chart__legend-entry"><span class="aui-chart__legend-item"><svg class="aui-chart__swatch" aria-hidden="true"/>Increase</span></li>
</ul>
<div class="aui-chart__body"> (height: --aui-chart-height)
<svg class="aui-chart__svg" role="group" aria-roledescription="waterfall chart" aria-labelledby="T" aria-describedby="D S">
<g class="aui-chart__grid" aria-hidden="true"/> <g class="aui-chart__axis …" aria-hidden="true"/>
<g class="aui-waterfall-chart__connectors" aria-hidden="true"><line class="aui-chart__connector"/>...</g>
<g class="aui-waterfall-chart__bars">
<g class="aui-waterfall-chart__step aui-waterfall-chart__step--increase aui-chart__series--c3"><rect class="aui-chart__mark aui-chart__bar" role="img" aria-label="Sales: +40 (Increase), running total 140" tabindex="0"/><rect class="aui-chart__pattern" aria-hidden="true"/></g>
<rect class="aui-chart__mark aui-waterfall-chart__gap" role="img" aria-label="Other: no value, running total 140"/>
</g>
<g class="aui-waterfall-chart__labels" aria-hidden="true"><text class="aui-chart__value-label">+40</text>...</g>
</svg>
<div class="aui-chart__empty" hidden/> <div class="aui-chart__tooltip" aria-hidden="true" hidden/>
</div>
<p class="aui-chart__summary" id="S" hidden>generated summary</p>
<div class="aui-chart__data">...Show data table...</div>
</div>
WaterfallChart.create(host: HTMLElement, options: WaterfallChartOptions): WaterfallChart

Global configuration key: waterfallChart (see Configuration).

Option Type Default Description
label string Chart title: visible text and the accessible name of the plot (aria-labelledby). Required.
hideLabel boolean false Visually hide the title; it stays the accessible name.
description string Visible description below the title, also referenced by aria-describedby (text only).
summary string Replaces the generated accessible summary (aria-describedby).
valueFormat Intl.NumberFormatOptions Number format for values in tooltips, labels, the data table, the summary, and axis ticks (ticks use fixed fraction digits).
formatValue (value: number) => string Custom value text; overrides valueFormat everywhere except axis ticks.
hiddenSeries readonly string[] Accepted and validated (string[]) for the shared chart contract; a waterfall has no series, so it has no effect.
steps readonly WaterfallStep[] Steps in order: { id, label, value?: number | null, kind?: ‘delta’ | ‘total’ }. Ids are unique and non-empty. delta (default): the change (null: a gap, the running total carries over). total: with a value, the running total becomes it (an opening balance); without, the bar shows the current running total. Required.
colors { increase?: ChartColor; decrease?: ChartColor; total?: ChartColor } Palette slots (1-8) per step kind. Default increase 3, decrease 2, total 1.
categoryAxis { label?: string } Category axis title (also the first table column header; default “Category”).
valueAxis { label?: string; min?: number; max?: number; tickCount?: number; includeZero?: boolean } Value axis title, fixed domain, and tick count (2-20). The domain always includes zero.
legend 'auto' | 'show' | 'hide' "auto" Legend of the step kinds present (Increase, Decrease, Total); not toggleable. auto and show display it, hide removes it. Globally configurable.
dataTable 'toggle' | 'visible' | 'hidden' | 'none' "toggle" Data table fallback with the exact data: behind a Show data table button (built on first open), always visible, visually hidden (screen readers only), or none. Globally configurable.
tooltip boolean true Tooltip on pointer hover and keyboard focus. Globally configurable.
patterns boolean false Texture fills (and dash patterns for lines) so marks never differ by color alone (always on in forced colors). Globally configurable.
height number 300 Plot height in CSS px (integer 120-2000); the width follows the container. Globally configurable.
valueLabels boolean true Signed change (deltas) or total printed above the bar (below for decreases and negative totals); a label wider than the step is omitted. Globally configurable.
connectors boolean true Dashed connectors (aria-hidden) from each step to the next at the running total; none into a total step. Globally configurable.
locale string "en-US" Number and message locale. Globally configurable. Inherited from common configuration.
direction 'ltr' | 'rtl' "ltr" rtl mirrors the category axis (first step at the right), puts the value axis on the right, and swaps ArrowLeft/ArrowRight. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement The host element.
element SVGSVGElement The plot (svg role=“group”), named by the title and described by the summary.
summary string The generated (or custom) accessible summary.
hiddenSeries string[] Always empty (a waterfall has no series).
Method Description
update(options: Partial<WaterfallChartOptions>): void Merge, validate, and re-render. Invalid options throw and keep the previous state. Keyboard focus stays on the same mark when it still exists.
setSeriesVisible(id: string, visible: boolean): void Inherited from the shared chart controller; no visible effect (a waterfall has no series).
destroy(): void Remove rendering, host classes, listeners, the resize observer, and the configuration subscription.

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-chart Host (shared chart chrome).
aui-waterfall-chart Host modifier for this chart type.
aui-chart--patterns patterns option on: textures (and dash patterns) shown.
aui-chart__header / __title / __title--hidden / __description Title and description.
aui-chart__legend / __legend-entry / __legend-item / __legend-item--hidden / __legend-label Legend list and its entries.
aui-chart__swatch aria-hidden legend and tooltip key (marker, dash, texture).
aui-chart__body / __svg / __layer Plot container (height from –aui-chart-height), SVG, and drawing layer.
aui-chart__grid / __gridline / __zero-line / __axis / __axis-line / __tick-label / __axis-title Axes (aria-hidden).
aui-chart__series--c1 ... --c8 Palette slot classes; set –aui-chart-color from color-chart-<n>.
aui-chart__mark / __mark--active / __mark--hover Focusable data mark and its states.
aui-chart__tooltip / __tooltip-title / __tooltip-rows / __tooltip-row / __tooltip-label / __tooltip-value Tooltip (aria-hidden; the focused mark carries the same text).
aui-chart__empty Empty state text (No data, All series are hidden).
aui-chart__summary Hidden summary referenced by aria-describedby.
aui-chart__data / __data--hidden / __table-toggle / __table-scroll / __table / __cell--numeric Data table fallback.
aui-chart__pattern / aui-chart__pattern-tile Texture overlays (aria-hidden).
aui-chart__bar / __line / __area / __point / __connector / __value-label Shared mark styles (chart-marks): bars, lines, areas, point markers, dashed connectors, printed values.
aui-waterfall-chart__bars / __step / __step--increase / __step--decrease / __step--total Bars layer and per-step groups by kind.
aui-waterfall-chart__gap Invisible focus target of a step without a value, on the running-total level.
aui-waterfall-chart__connectors / __labels Connector and value label layers (aria-hidden).

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-chart-1 | --aui-color-chart-2 | --aui-color-chart-3 | --aui-color-chart-4 | --aui-color-chart-5 | --aui-color-chart-6 | --aui-color-chart-7 | --aui-color-chart-8 | --aui-color-chart-axis | --aui-color-chart-grid | --aui-color-focus-ring | --aui-color-hover | --aui-color-link | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-font-weight-regular | --aui-font-weight-semibold | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-tooltip-max-width | --aui-touch-target-min

type WaterfallStepKind = 'delta' | 'total';
interface WaterfallStep { id: string; label: string; value?: number | null; kind?: WaterfallStepKind }
interface WaterfallChartColors { increase?: ChartColor; decrease?: ChartColor; total?: ChartColor }
interface WaterfallChartConfig { legend: ChartLegendMode; dataTable: ChartTableMode; tooltip: boolean; patterns: boolean; height: number; valueLabels: boolean; connectors: boolean }
interface WaterfallChartOptions extends ChartCommonOptions, Partial<WaterfallChartConfig> {
steps: readonly WaterfallStep[];
colors?: WaterfallChartColors;
categoryAxis?: { label?: string };
valueAxis?: WaterfallChartValueAxis; // { label?; min?; max?; tickCount?; includeZero? }
}

Pattern: SVG chart as a named, described group (role=“group” with aria-roledescription) of role=“img” data marks with roving focus; data table fallback (native table). Follows the WAI Complex Images tutorial (short name plus long description) and the roving tabindex technique of WAI-ARIA APG.

Key Context Action
ArrowLeft / ArrowRight (also ArrowUp / ArrowDown) Step focused Previous / next step; Left/Right are mirrored in RTL. Steps without a value are reachable too.
Home / End Step focused First / last step.
PageUp / PageDown Step focused Ten steps back / forward.
Escape Tooltip visible Hides the tooltip without moving focus (WCAG 1.4.13); it returns on the next move.
Tab / Shift+Tab Any One tab stop for the plot (the active step), then the Show data table button and table region.
Element Role
svg.aui-chart__svg group with aria-roledescription (localized chart type), named by the title
data marks img with an aria-label: step, signed change, kind, and running total (totals: the total)
legend list (ul) named “Legend” of the step kinds; entries are text (not toggleable)
axes, connectors, value labels, textures, tooltip aria-hidden (decorative duplicates of the accessible data)
data table table (native) with caption, column headers, and row headers; wide tables scroll in a focusable region
Attribute Element Value
aria-labelledby svg id of the visible (or visually hidden) title
aria-describedby svg description id (when provided) and the generated summary id
aria-roledescription svg Localized “waterfall chart”
aria-label each mark Localized “{label}: {change} ({kind}), running total {total}”; totals “{label}: total {total}”; gaps “{label}: no value, running total {total}”. Example: “Closing: total 125”
tabindex active mark 0 on exactly one mark (roving); other marks have none
aria-expanded / aria-controls Show data table button Table open state and the table region id

Roving focus: one step is in the tab sequence and remembers the last visited step across re-renders (resize, update). Toggling the table keeps focus on the table button.

Criterion Level Note
1.1.1 Non-text Content A
1.3.1 Info and Relationships A
1.4.1 Use of Color A
1.4.3 Contrast (Minimum) AA
1.4.10 Reflow AA
1.4.11 Non-text Contrast AA
1.4.13 Content on Hover or Focus AA
2.1.1 Keyboard A
2.4.3 Focus Order A
2.4.7 Focus Visible AA
4.1.2 Name, Role, Value A

Automated test results: Accessibility and compliance.

  • The generated summary names the chart type, step count, start and end values, and the largest increase and decrease with their steps.
  • Increases, decreases, and totals differ by color, by texture (patterns), by signed value labels, and by their accessible names and table Type column, never by color alone.
  • Forced colors: marks use CanvasText (bubbles and outlines Canvas/CanvasText) and keep shapes and textures; focus uses Highlight.
  • No animation: nothing moves on render; hover and focus emphasis transitions are removed under prefers-reduced-motion and animation: none.
  • Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
  • aria-roledescription support varies; screen readers without it announce “group”.

default, empty (“No data”), step focused (tooltip), hovered, table open.

From Trigger To
plot not focused Tab active step focused, tooltip shown
step focused arrow keys, Home, End, PageUp, PageDown another step focused
tooltip visible Escape tooltip hidden, focus unchanged
table closed Show data table table built and shown
any container resize re-render at the new width; focus kept on the same step
  • The summary names the type, step count, start and end values, and the largest increase and decrease, for example “waterfall chart, 5 steps. Starts at 100, ends at 125. Largest increase: Sales (+40). Largest decrease: Refunds (-15).”
  • Increases, decreases, and totals differ by color, texture, signed labels, accessible names, and the table’s Type column.
  • Forced colors use CanvasText and keep textures; focus uses Highlight. Nothing animates.
  • Manual screen-reader verification is pending.

The width follows the container (ResizeObserver); the height is height. Category labels thin and truncate with the band width; value labels wider than about one step are omitted. Reflows at 320 CSS px.

direction: 'rtl' mirrors the category axis (first step at the right), puts the value axis on the right, mirrors connectors, and swaps ArrowLeft/ArrowRight.

Kind colors come from color-chart-<n> via colors (increase 3, decrease 2, total 1 by default). Connectors use color-chart-axis; value labels color-text with a surface halo.

configureAbsoluteUI({ components: { waterfallChart: { connectors: false, valueLabels: true, height: 280 } } });

Changes apply to existing instances immediately.

Instance options override global and theme defaults. All options are dynamic.

Not applicable: steps are text categories; no dates are formatted.

None. Legend keys are drawn shapes; no toolbar is shown.

All text uses textContent; SVG is built with createElementNS. Colors are classes; sizes and the tooltip position are written through the CSSOM. No innerHTML, style attributes, or inline handlers.

Renders the given data only; no persistence, network access, or telemetry. Validation errors name the option, never its value.

Budget: WaterfallChart.create with 200 steps under 40 ms in headless Chromium, including the first render (e2e performance test, tests/e2e/perf-r3.spec.ts). One DOM node per step; the data table is built only when opened in toggle mode.

Tested with 200 steps; labels thin out on narrow plots.

  • No steps, or only steps without a value: “No data”.
  • A delta of null is a gap: no bar, an invisible focus target at the running total, the total carries over.
  • A zero change is drawn as a 1 px bar and labelled “Increase”.
  • Negative running totals: the domain crosses zero; decreases and negative totals put their labels below the bar.
  • The first delta starts from zero; a leading total with a value sets the opening balance.
Code Category Cause
WATERFALL_CHART_OPTIONS configuration Missing label; steps not an array; step ids not unique or empty; non-string labels; non-numeric values; invalid kind; colors outside 1-8; invalid axis options.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid or unknown configuration.

A failed construction leaves the host untouched; a failed update() keeps the previous state.

  • One sequence per chart; no series or legend toggling.
  • Totals always start at zero.
  • Value labels are omitted when wider than the step.
  • Manual screen-reader verification is pending.
  • Horizontal orientation; grouped or stacked waterfalls.
  • Zoom, pan, and crosshair.
  • HTML in labels or tooltips.