Skip to content
microcharts
ReferenceFrontierTraceFold

TraceFold

React trace fold chart — one rect per span by start, duration, and depth — a folded trace. Tiny accessible SVG microchart; RSC-safe static or /interactive.

TraceFold answers "where did the latency go — which spans, at which depth, on the path that actually determined the total?". Each span is a rect placed by its start time, sized by its duration, and stacked by its nesting depth. The critical path — the chain of spans that bound the total — is accented and everything else muted, so the answer to "which spans mattered" is immediate.

TraceFold
interactive · 5.13 kB · static · 2.46 kB

Install

Import & usereact/trace-fold
import { TraceFold } from "@microcharts/react/trace-fold";// spans — real values under “Sample data” below<TraceFold data={spans} title="Request trace" />
Sample data
const spans = [  { label: "request", start: 0, duration: 214, depth: 0 },  { label: "db.query", start: 10, duration: 86, depth: 1, parent: 0 },  { label: "auth", start: 0, duration: 8, depth: 1, parent: 0 },  { label: "render", start: 96, duration: 60, depth: 1, parent: 0 },  { label: "serialize", start: 156, duration: 40, depth: 1, parent: 0 },  { label: "index-scan", start: 12, duration: 70, depth: 2, parent: 1 },  { label: "decode", start: 82, duration: 12, depth: 2, parent: 1 },  { label: "log", start: 200, duration: 14, depth: 1, parent: 0 },  { label: "gc", start: 90, duration: 5, depth: 2, parent: 1 },];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — request traces, flame charts, p95-exemplar latency breakdowns.
  • Avoid for — a single duration (Bullet) or a time series (Sparkline).

Sizing

Variants

structure audit
locale

format also takes Intl.NumberFormatOptions — with a locale, the accessible summary's numbers follow that locale's own grouping and decimal marks ("14.868 ms" in German, not "14,868 ms"). In-rect text stays the plain span label either way; only the announced numbers are localized.

Edge cases

single span
labels drop out

Four homes

Why this default

Accenting the critical path because "which spans mattered" is the question a uniform flame strip doesn't answer — the eye goes straight to the chain that set the total. Widths are durations on one linear shared time scale, never per-row normalized, so a wide span is genuinely a slow span. The only documented width distortion is a one-unit floor for zero-duration spans, and the critical-path walk is deterministic (ties resolve to the earliest start).

Accessibility

The accessible name names the biggest span and its path status — "4 spans over 214 ms; longest db.query (86 ms) on the critical path." The interactive entry roves spans within a depth with ←/→ and between depths with ↑/↓, announcing each span's duration, share of the total, depth, and whether it is on the critical path.

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*Span[]Flat span list; parent = index.
emphasis"critical" | "none"Mute non-critical spans, or uniform.
labelsbooleanWidth-gated in-rect labels.
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