Treemap
A nested-rectangle treemap that visualises hierarchical sizes by area. Containers frame their children; leaf rects fill in proportional to their value. The classic squarify algorithm keeps aspect ratios as close to 1:1 as the parent will allow, so every rect stays readable even at deep nesting levels.
framework
react-dom
react
app
components
pages
vendor
Customize
Layout
8px
Display
Installation
npx shadcn@latest add https://craftbits.dev/r/treemap.jsonUsage
import { Treemap } from "@craft-bits/core";
const nodes = [
{
id: "framework",
label: "framework",
children: [
{ id: "react", label: "react", value: 42 },
{ id: "react-dom", label: "react-dom", value: 130 },
],
},
{ id: "router", label: "router", value: 22 },
];
<Treemap nodes={nodes} width={560} height={320} />Pulse a region during narration:
<Treemap
nodes={nodes}
width={560}
height={320}
highlightedIds={new Set(["react-dom"])}
/>Understanding the component
- Squarify layout. Children of every container are packed by the Bruls/Huijing/van Wijk squarify algorithm — the row with the worst aspect ratio is committed first, then the algorithm slices the remaining short side. The result is rectangles whose proportions stay close to 1:1 rather than the thin slivers a naive slice-and-dice layout produces.
- Containers and leaves coexist. A node with
childrenis a container — its area is the sum of its descendants and its rect is drawn as a transparent outline. A node withvalueis a leaf and is filled. Containers carry a small inner padding so nested children sit visibly inside the parent frame. layoutIdper rect. Every rect is keyed byidso when the caller swaps thenodesprop between snapshots (abeforevsaftera tree-shake), the rects glide between layouts viaSPRINGS.smoothinstead of cross-fading.- Adaptive labels. Labels are pruned when the rect drops below 48 by 24 pixels. Pass
hideLabelsto skip them entirely (useful when the treemap is small or part of a comparison strip). - Highlight by id.
highlightedIdsaccepts aReadonlySetof ids; matching rects render in the accent color so narration can point at a region without dropping the rest. - Reduced motion. Layout transitions and rect entrances collapse to a zero-duration transition, so the final state is reachable without animation.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
nodes | readonly TreemapNode[] | required | Top-level nodes. Each is a leaf (with value) or a container (with children). |
width | number | 640 | Outer canvas width in pixels. |
height | number | 360 | Outer canvas height in pixels. |
padding | number | 8 | Inner padding applied inside container rects so children sit visibly inside the frame. |
highlightedIds | ReadonlySet<string> | — | Set of node ids to render in the accent color. |
hideLabels | boolean | false | Suppress all labels (useful for tiny canvases). |
className | string | — | Merged onto the outer <div> via cn(). |
Accessibility
- The root is
role="img"with anaria-labelsummarising the number of regions, the total weight, and the five largest leaf labels. Screen-reader users hear the shape of the data without having to parse the visual encoding. - Rect colors are not the only signal — containers and leaves are distinguishable by border treatment and fill alpha, and highlighted regions carry a thicker accent border.
- Interior rects carry
role="presentation"so the screen reader treats the root as the single semantic image rather than reading every rect as a separate node. - Motion respects
prefers-reduced-motion: layout transitions and rect entrances collapse to a zero-duration transition.
Credits
- Extracted from:
terminal-dreams(src/components/frontend-design/perf-bundle/ui/Treemap.tsx). The source coupled the component to a domain-specificBundleSimulatorlayout type with chunk frames, cache badges, and tree-shake state baked in. The library version drops every project-specific concern, generalises the input to a recursive{ id, label, value, children?, color? }shape, computes the layout in-component via squarify, and keeps the originallayoutId-per-rect transition story.