Skip to main content

WaterfallChart

WaterfallChart

How a starting value moves through increases and decreases to a total

Tags: chart waterfall bridge variance finance reporting

View Demo

The WaterfallChart shows how a starting value moves through a series of increases and decreases to a total, with each step floating from the running total before it. Use it for margin bridges (sale price to gross margin), budget variance, or backlog movement (opening backlog, sales, cancellations, closings, closing backlog).

Svelte only (@classic-homes/charts-svelte); React support is pending.

Import​

<script>
  import { WaterfallChart } from '@classic-homes/charts-svelte';
</script>

Basic Usage​

<script>
  import { WaterfallChart } from '@classic-homes/charts-svelte';

  const data = [
    { name: 'Base price', value: 412000, isTotal: 'value' },
    { name: 'Options', value: 38500 },
    { name: 'Lot premium', value: 15000 },
    { name: 'Incentives', value: -12000 },
    { name: 'Net revenue', isTotal: true, value: 0 },
    { name: 'Direct costs', value: -318000 },
    { name: 'Gross margin', isTotal: true, value: 0 },
  ];
</script>

<WaterfallChart title="Average Margin Bridge" {data} valueFormat="currency" />

Props​

Chart-Specific Props​

Prop Type Default Description
data WaterfallStep[] required Steps in order
showLabels boolean true Show each step's signed change (or total) on its bar
labelFormatter string | ((params: LabelFormatterParams) => string) - Label function; receives the step's change (or total) as value. String templates are not applied
increaseColor string - Colour for increases (defaults to the success colour)
decreaseColor string - Colour for decreases (defaults to the destructive colour)
totalColor string - Colour for totals (defaults to the first series colour)
xAxisConfig AxisConfig - Step axis customisation
yAxisConfig AxisConfig - Value axis customisation
referenceLines ReferenceLine[] - Lines marking targets or thresholds
referenceBands ReferenceBand[] - Shaded value ranges
onClick (params: DataPointEventParams) => void - Callback when a step is clicked; value is the step's change (or total)

Inherited Base Props​

Prop Type Default Description
title string required Chart title for accessibility (aria-label)
description string - Description for screen readers (generated from the data when omitted)
height number | string 400 Chart height in pixels or CSS value
minHeight number - Minimum height in pixels; also bounds an 'auto' height
maxHeight number - Maximum height in pixels; also bounds an 'auto' height
loading boolean false Show loading skeleton (an overlay when data is already shown)
error string | null - Error message to display
onRetry () => void - Show a Retry button on the error state, calling this
emptyMessage string - Message shown when data is empty
theme 'light' | 'dark' | 'auto' 'auto' Theme preference
animation boolean true Enable/disable animations (respects prefers-reduced-motion)
showTooltip boolean true Show tooltip on hover
showGrid boolean true Show grid lines
valueFormat ValueFormat - Preset ('number', 'integer', 'compact', 'currency', 'currencyCents', 'percent', 'percentValue', 'days'), Intl.NumberFormatOptions or a function; drives the value axis, tooltip, labels and data table
locale string 'en-US' Locale for valueFormat
tooltipFormatter string | ((items: TooltipFormatterParams[]) => string) - Custom tooltip template or HTML function
tooltipValueFormatter (value: number) => string - Format values in the default tooltip (overrides valueFormat there)
option EChartsOption - Raw ECharts option deep-merged over the generated one
onReady (chart: EChartsType) => void - Called with the ECharts instance when it is created
events ChartEventHandlers - Raw ECharts event handlers keyed by event name ('datazoom', 'legendselectchanged', ...)
showDataTable boolean | 'sr-only' 'sr-only' Data table for screen readers only, a visible "Show data" toggle (true) or none (false)
exportable boolean | ChartExportConfig - Show PNG and CSV download buttons, or { image, csv, filename }
patterns boolean false Fill series with decal patterns as well as colour
class string - Custom CSS class
showLegend boolean - Show chart legend

Data Structure​

interface WaterfallStep {
  name: string; // Step label
  value: number; // Change contributed by this step (ignored for isTotal: true)
  isTotal?: boolean | 'value'; // true: bar from zero to the running total
  //                              'value': bar from zero to `value`, resetting the running total
  color?: string; // Override the bar colour
  label?: string; // Label text shown instead of the formatted value
}

Examples​

Backlog Movement​

Start with isTotal: 'value' to set the opening balance, and end with isTotal: true to show where the steps land.

<WaterfallChart
  title="Backlog Movement, Q3"
  data={[
    { name: 'Opening backlog', value: 214, isTotal: 'value' },
    { name: 'Sales', value: 96 },
    { name: 'Cancellations', value: -14 },
    { name: 'Closings', value: -88 },
    { name: 'Closing backlog', value: 0, isTotal: true },
  ]}
  valueFormat="integer"
/>

Custom Colours and Labels​

<WaterfallChart
  title="Budget Variance"
  {data}
  increaseColor="#15803d"
  decreaseColor="#b91c1c"
  totalColor="#334155"
  valueFormat="compact"
/>

Layout Without the Chart​

waterfallLayout returns where each bar sits (start, end, change and kind), for tables or custom rendering.

import { waterfallLayout } from '@classic-homes/charts-svelte';

waterfallLayout([
  { name: 'Start', value: 100, isTotal: 'value' },
  { name: 'Change', value: -30 },
  { name: 'End', value: 0, isTotal: true },
]);
// [{ start: 0, end: 100, kind: 'total', ... }, { start: 100, end: 70, kind: 'decrease', ... }, ...]

Accessibility​

  • The title prop is used as aria-label; a description counting increases and decreases and stating the final total is generated when description is omitted
  • Steps, changes and running totals are rendered as a screen-reader table (showDataTable)
  • Labels carry a sign (+/−), so direction does not rely on colour alone
  • Animations respect prefers-reduced-motion
On this page