Skip to content
microcharts
ReferenceDecisionBurnChart

BurnChart

React burn chart chart — sprint plan vs actual with a provisional projection to the deadline. Tiny accessible SVG microchart; RSC-safe static or /interactive.

BurnChart answers "will we finish on time?". It draws the plan line (dashed, full length to the deadline), the actual line to today, and a dotted projection whose slope is a plain linear fit over the last few actual points — provisional by construction, never a smoothed or optimistic curve. The gap label states the signed schedule landing, because "will we finish" is a number, not a vibe.

BurnChart
interactive · 5.93 kB · static · 3.41 kB

Install

Import & usereact/burn-chart
import { BurnChart } from "@microcharts/react/burn-chart";// plan, actual — real values under “Sample data” below<BurnChart data={{ plan, actual }} title="Sprint 12" />
Sample data
// an 11-day sprint burning down; 6 days in, slightly behind → projected 2 days lateconst plan = [40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0];const actual = [40, 35, 31, 27, 24, 21];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — a sprint burndown in a tab header, will-we-finish in a KPI card, plan vs actual with a projected landing.
  • Avoid for — a single progress number (Progress) or a plain series (Sparkline).

Sizing

Variants

retrospective + burn-up
locale

With a locale, the accessible summary's numbers follow that locale's own grouping — "2.300" in German, not "2,300".

Edge cases

no plan yet
stalled burn
day one

With no plan (plan: []), the projection still runs — the fitted slope only needs actual — but there's nothing to compare it to, so the summary drops the "vs planned" clause. A stalled burn (actual flat) never reaches zero, so finishes is false and the summary states that plainly rather than extrapolating a fake landing. A single actual point draws no projection at all (the fit needs at least two).

Four homes

Why this default

The gap label, because "will we finish" is a number, not a vibe. History is drawn solid and exact; the projection is dotted, muted, and computed as a linear fit over the last max(2, ⌈actual/3⌉) actual points — a stated method, never an optimistic hand-drawn curve. When the recent burn flattens, the projection never reaches zero and the summary says so outright ("not finishing at the current pace"), rather than implying a landing that isn't coming.

Accessibility

The accessible name states progress against the plan and the projected landing — "6 of 11 days in: 19 points done vs 20 planned — projected to finish 2 days late.". The interactive entry steps the days; history announces actual vs plan, and the dotted region announces the projection.

The interactive entry follows the shared interaction contract: arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*{ plan: number[]; actual: number[] }Remaining work per period (mode='down') or completed (mode='up').
mode"down" | "up"Burn-down (remaining → 0, default) or burn-up (done → scope).
projectionbooleanThe dotted extrapolation to the deadline (default true).
workstringWork-unit noun for the summary and readout. Defaults to `strings.burnWork` ('points' in EN), so a localized bundle replaces it.
unitstringPeriod noun for the summary and gap label (default 'day').
label"gap" | "none"Signed schedule landing vs the deadline in a right gutter.
animatebooleaninteractiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion.

Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.

Related charts