Components

Waterfall chart

A bridge/waterfall chart: a dumb painter over pre-computed data. Totals anchor in navy, movements read as signed increases and decreases against them. Colour, ordering and labels are the renderer's decisions; the caller supplies only the resolved bars and the y-domain.

Install

npx shadcn@latest add @alix/waterfall

Preview

Usage

import { WaterfallChart, type WaterfallDatum } from "@/components/ui/waterfall";

// Each bar is pre-computed: base is the invisible riser, value the visible height.
const data: WaterfallDatum[] = [
  { name: "FY24", base: 0, value: 46, label: "46", kind: "total" },
  { name: "Volume", base: 46, value: 9, label: "+9", kind: "increase" },
  { name: "Price", base: 51, value: 4, label: "−4", kind: "decrease" },
  // …
  { name: "FY25", base: 0, value: 53, label: "53", kind: "total" },
];

<WaterfallChart data={data} domain={[0, 68]} />

Examples

01

Inside a panel

Panel owns the dashboard frame; the chart fills a fixed-height body. The same bridge, at dashboard scale rather than slide scale.

EBITDA bridge

FY24 to FY25, £m

<Panel title="EBITDA bridge" description="FY24 to FY25, £m" flush>
  <div className="h-64 w-full p-4">
    <WaterfallChart data={data} domain={domain} />
  </div>
</Panel>
02

A cost bridge

The kinds (total, increase, decrease) are the only palette lever, so a cost-down bridge and a revenue bridge read the same way.

const data: WaterfallDatum[] = [
  { name: "Baseline", base: 0, value: 120, label: "120", kind: "total" },
  { name: "Procurement", base: 112, value: 8, label: "−8", kind: "decrease" },
  { name: "Inflation", base: 103, value: 6, label: "+6", kind: "increase" },
  { name: "Run-rate", base: 0, value: 109, label: "109", kind: "total" },
];

When to use it

Use it for

  • A quantified bridge where the bars are already computed (a running level between signed movements).
  • Inside WaterfallSlide (the deck) or a Panel body (a dashboard). Supply a height on the wrapper.
  • A y-domain with a little headroom above the tallest bar so the value labels clear the frame.

Reach for something else

  • Computing the bridge in the chart: it's a painter; build base/value/kind upstream.
  • Per-bar colour requests: the palette is fixed by kind (totals navy, movements the ramp).
  • A continuous trend or a category comparison. Use Chart, and StatsSlide for headline figures.

Props

PropTypeDefaultDescription
dataWaterfallDatum[]Pre-computed bars: name, base (the invisible riser), value (the visible height), a signed display label, and kind (total | increase | decrease) which selects the fill.
domain[number, number]The y-axis domain, computed upstream from the bars, typically [min(0, base), peak × 1.12] so labels clear the top.

See also