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";
Markdown
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/ui

Usage

example.tsx
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-1 to --color-chart-4, which has light and dark values. Override --sg-chart-1 to --sg-chart-4 on any ancestor to rebrand a chart. Pair color with labels, since the palette is not tuned for every type of color vision.

Also in charts