Skip to content
microcharts
ReferenceExpressiveTreeRings

TreeRings

TreeRings draws one ring per period, oldest at the center, with each ring's thickness set by its value.

encodes
radial ring thickness ∝ per-period value
precision
medium
nodes
≤ 4 (merged ring path + highlighted ring + centre dot + label)

TreeRings shows how growth accumulated period over period, the way a tree records it: one ring per period, oldest at the center, each ring's thickness carrying that period's value. The channel is thickness, not area: equal thickness at a larger radius spans more area (the ring illusion), so read the thicknesses rather than the wedges. The current period is drawn 1.5× heavier in the accent color, weight and color together. For exact per-period reads use SparkBar.

TreeRings
interactive · 4.76 kB · static · 2.34 kB

Install

Import & usereact/tree-rings
import { TreeRings } from "@microcharts/react/tree-rings";// years — real values under “Sample data” below<TreeRings data={years} unit="years" periodWord="year" title="Account age" />
Sample data
const years = [8, 12, 10, 18, 22, 15, 20, 14];
Needs package + stylesheetSet up with AI

Try it

When to use it

Use it for account or company age, a cohort-age marker in a table cell, or a per-period growth story in a KPI card. Avoid it for exact per-period reads (SparkBar), for more than twenty-four periods, and for non-cumulative series.

Sizing

Variants

filled annuli + cohort age (total)

Stroke rings are the default: at twenty-four pixels, hairlines keep the disc quiet and let the accent ring stay loud. rings="fill" draws filled annuli instead. Pass total for the cohort-age story, and the disc fills only Σdata/total of the radius, so a young account reads as part-grown.

locale — the last-value label and the summary both follow it

Edge cases

a zero-value period collapses cleanly, it isn't padded to a minimum ring
no data yet

TreeRings enforces no minimum visual thickness. A near-zero period looks near-zero, and a zero-value period collapses its two boundaries onto each other.

Four homes

Accessibility

The accessible name summarizes the growth: "8 periods; latest 14, biggest 22 in period 5." The interactive entry steps the rings from the center out with ←/→ (or hover), announcing each period as "Year 5: 22."

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*number[]Per-period growth, oldest first.
highlight"last" | "none" | numberWhich period's ring to pick out.
totalnumberExpected lifetime Σ — the disc fills only Σdata/total.
rings"stroke" | "fill"Boundary rings (default) or filled annuli.
periodWordstringSingular period noun for the summary (default "period").
unitstringPlural period noun for the summary (default "periods").
sizenumberRings box edge in viewBox units (default 24).
fontSizenumberType size of the gutter label, in viewBox units. Defaults from `size`.
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