Treemap
A squarified treemap: click to drill and the tiles grow to fill the view, with a breadcrumb back and metrics that morph every tile.
import { Treemap } from "@sagui/ui";Loading demo
When to use
- Many parts where the biggest ones matter and people drill for detail.
- Showing size and a second measure at once.
When not to use
- Use bar-chart when exact comparisons between similar values matter.
- Use sunburst when the depth of the hierarchy is the story.
Installation
Install the package and import the styles once. The installation guide covers the Tailwind setup.
$ npm install @sagui/uiUsage
import { Treemap } from "@sagui/ui";
const data = {
id: "all", label: "All regions",
children: [
{ id: "na", label: "North America", children: [{ id: "us", label: "United States", value: 18400, color: 24 }, { id: "ca", label: "Canada", value: 2350, color: 19 }] },
{ id: "eu", label: "Europe", children: [{ id: "de", label: "Germany", value: 4120, color: 28 }] },
],
};
export function Revenue() {
return <Treemap data={data} label="ARR" colorLabel="Growth" formatColor={value => `+${value}%`} />;
}Examples
Starting inside a branch
defaultFocus opens the map already drilled into a branch. Without colorLabel every tile shares its branch hue.
Loading demo
API reference
Treemap
A squarified treemap of a hierarchy. Click a branch and its tile grows to fill the view while its children open inside; the breadcrumb zooms back out. Switching the size or shading measure morphs every tile.
| Prop | Type | Default | Description |
|---|---|---|---|
data (required) |
TreemapNode |
– | The root: { id, label, value?, color?, children? }. A branch's value is the sum of its children. |
label (required) |
string |
– | What the whole is. Names the chart for assistive technology. |
formatValue |
(value: number) => string |
– | Formats sizes on tiles, the total, and the tooltip. |
colorLabel |
string |
– | Names the shading measure, such as "Growth". Tiles take the hue of their top level branch and deepen with the measure. Leave it out for one depth. |
formatColor |
(value: number) => string |
– | Formats the shading measure. |
colorDomain |
[number, number] |
– | Range of the shading measure. Defaults to the range of the leaves. |
focus |
string |
– | Controlled id of the node that fills the view. |
defaultFocus |
string |
– | Initial focus when uncontrolled. Defaults to the root. |
onFocusChange |
(id: string) => void |
– | Called when people drill in or out. |
height |
number |
420 |
Height of the tiles in pixels. |
emptyLabel |
string |
"No data yet" |
Shown when every value is zero. |
className |
string |
– | Extra class on the root figure. |
Keyboard interactions
| Keys | Action |
|---|---|
| Arrow keys | Move to the nearest top level tile in that direction. |
| HomeorEnd | Move to the first or last tile. |
| EnterorSpace | Zooms into the tile in focus. |
| EscapeorBackspace | Zooms out one level. |
Accessibility
- The tiles form a focusable group with a description of its keys; the breadcrumb is a nav with aria-current on the current level.
- The tile in focus is announced with its path, value, share of parent, and shading measure through a polite live region.
- A visually hidden table lists every node's path, value, share, and measure.
Motion
- Drilling in carries every tile through one affine zoom: the chosen tile grows to fill the view, its siblings fly outward, and its children open inside it.
- Zooming out reverses the same path, so each level shrinks back into the tile it came from.
- Changing a measure re-lays out the same ids, so tiles resize and recolor in place; totals roll and breadcrumbs slide.
- Text never scales: tiles are sized each frame and labels appear only where they fit. Reduced motion places tiles immediately.
Responsive behavior
- The layout squarifies to the measured width, so tiles stay close to square on any screen; headers and labels hide where they would not fit.
- Tap a tile to read it, tap a branch to drill in.
Performance
- Layouts are computed per focus; animation interpolates rects and writes transforms and sizes directly. Comfortable up to a few hundred nodes.
Notes
- Choose it for part-to-whole across a hierarchy with many leaves, such as revenue by region, country, and plan.
- Give nodes stable ids so switching the size measure morphs rather than rebuilds.
- The shading measure should be a magnitude (growth, margin), not identity; identity comes from the top level hue.
- Colors come from the chart palette,
--color-chart-1to--color-chart-4, which has light and dark values. Override--sg-chart-1to--sg-chart-4on any ancestor to rebrand a chart. Pair color with labels, since the palette is not tuned for every type of color vision.