caliper uidocs

Stacked area chart

Free

Parts of a whole over time, stacked from the baseline. Switching between values and share morphs the same layers, so growth and share read as one picture.

Installs components/ui/stacked-area-chart.tsxDepends on d3-shapeMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/stacked-area-chart.json
MRR by plan, 2026 ($k)

MRR by plan, 2026 ($k)
PeriodStarterTeamEnterpriseTotal
Jan18243072
Feb20.227.130.5577.85
Mar22.430.232.284.8
Apr21.633.334.9589.85
May23.836.438.899
Jun2639.543.75109.25
Jul25.242.649.8117.6
Aug27.445.756.95130.05
Sep29.648.865.2143.60000000000002
Oct28.79999999999999751.90000000000000674.55000000000001155.25
Nov315585171
Dec33.258.196.55000000000001187.85000000000002

When to use #

Use it for

  • Revenue by plan, traffic by source or spend by team across months.
  • Questions about both size and mix.

Skip it when

  • Series that do not add up to a total; use the line chart.
  • More than five or six layers; the middle ones become unreadable.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/stacked-area-chart.json

Adds its 7 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { StackedAreaChart } from "@/components/ui/stacked-area-chart"

const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

const planMix = months.map((label, i) => ({
  id: label,
  label,
  values: { starter: 18 + i * 1.2 + (i % 3), team: 24 + i * 3.1, enterprise: 30 + i * i * 0.55 },
}));

const plans = [
  { id: "starter", label: "Starter" },
  { id: "team", label: "Team" },
  { id: "enterprise", label: "Enterprise" },
];

export function StackedAreaChartDemo() {
  return <StackedAreaChart label="MRR by plan, 2026 ($k)" data={planMix} series={plans} formatValue={(v) => `$${Math.round(v)}k`} className="w-full" />;
}

API reference #

StackedAreaChart

component
PropTypeDefault
label *string—
data *readonly ChartDatum[]—
series *readonly ChartSeries[]—
unitstring""
mode"values" | "share""values"
heightnumber260
formatValue((value: number) => string)numberText
loadingboolean—
errorstring—
classNamestring—

Accessibility #

It exposes group and status semantics, with aria-label, aria-busy and aria-hidden kept in step with state. Changes that matter are announced through a live region.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.