Charts
TreemapChart
Part of a whole, when the whole has too many parts for a pie — and the parts nest.
Usage
When to reach for it
Ships from@misoto22/design/charts
import { TreemapChart } from '@misoto22/design/charts'Notes
Part of a whole, when the whole has too many parts for a pie — and the parts nest.
A treemap encodes value as AREA, which the eye reads worse than length but far better than angle, and it is the only form here that stays readable at fifty items. Two rules make it honest: no negative values (an area cannot be negative), and the tiles have to sum to something a reader recognises as the whole.
Reach for <BarChart> when there are under a dozen items and the ranking matters — a bar's length is the more precise encoding, and a treemap's layout deliberately does not order its tiles by value alone.
Anatomy
| Element | Description |
|---|---|
| Figure framerequired | ChartFigure’s <figure>, named by title, wrapping one ChartContainer. |
| Tilesrequired | The root’s own tile renderer. The gap between tiles is a 2px --chart-surface STROKE rather than a smaller rect, so the tiles still tile — a treemap whose parts do not touch stops reading as a partition of one whole. |
| Tile labels | showLabels, on by default, but a tile is only labelled when it is wider than 56px and taller than 26px. Below that the name is dropped rather than clipped, so the long tail is unlabelled by design. |
| Tooltip | <TreemapChart.Tooltip>, keyed on the tile name. It is doing more work here than elsewhere: it is the only way to name a tile too small to carry its own label. |
| Hidden data tablerequired | The sr-only table lists the LEAVES, each with the path that names it. A nested tree read row by row is not something anyone can follow, so the hierarchy is flattened into the row header instead. |
| Paint | variant="ramp" walks --series-1 to --series-8 by tile INDEX; variant="nested" steps by DEPTH instead, which is the right encoding once the question is what is inside what. |
Best practices
Do
- Feed it non-negative values that sum to something the reader recognises as the whole. Area is the encoding, an area cannot be negative, and a leaf at zero or below is laid out at zero width and dropped from the picture — the hidden table prints it as “not drawn” rather than letting the two views disagree about how many leaves there are.
- Compose <TreemapChart.Tooltip> whenever there is a tail. Anything under 56 by 26 pixels carries no label at all, and on a fifty-item treemap that is most of it.
- Switch to variant="nested" once the tree has a second level. ramp keys the fill off the tile index, so it separates siblings and says nothing at all about depth.
Don’t
- Do not read the ramp as a key. The slot is index modulo eight, so tile one and tile nine are painted identically — the fill here is separation, not identity, and the picture will not correct a reader who assumes otherwise.
- Do not reach for it to rank a dozen items. A bar’s length is read far more precisely than a rectangle’s area, and the squarify layout deliberately does not order tiles by value alone, so a reader cannot even scan them in order.
Examples
default
Eight packages as one partition of a whole. A treemap encodes value as area, which the eye reads worse than length and far better than angle, and it is the only form here that stays readable at fifty items. Two rules keep it honest: no negative values, because an area cannot be negative, and the tiles have to sum to something the reader recognises as the whole — under a dozen items with a ranking to read, a BarChart is the more precise encoding, since a treemap deliberately does not order its tiles by value alone.
| path | Value |
|---|---|
| recharts | 480 |
| react-dom | 310 |
| motion | 140 |
| @remixicon/react | 96 |
| cmdk | 62 |
| tailwind-merge | 41 |
| clsx | 12 |
| sonner | 28 |
nested
Two levels, and the two ways of painting them. ramp walks the series ramp so siblings separate by lightness, which is what a flat set of tiles wants; nested darkens by depth instead, so every tile at one level shares a weight and the question the paint answers becomes what is inside what. Only the leaves carry a size — a branch is the sum of its children — and the hidden data table is flattened to those leaves, because a nested tree read aloud row by row is not something anyone can follow.
| path | Value |
|---|---|
| runtime › react-dom | 310 |
| runtime › react | 92 |
| charts › recharts | 480 |
| charts › motion | 140 |
| ui › @remixicon/react | 96 |
| ui › cmdk | 62 |
| ui › sonner | 28 |
| ui › clsx | 12 |
many small tiles
The long tail, which is where a treemap earns its place and also where it stops naming itself: a tile is only labelled once it is wider than 56 pixels and taller than 26, so the two files that carry this route are named and most of the other eighteen are anonymous rectangles. The tooltip names one at a time under the pointer, and the hidden data table — generated from the same leaves the tiles are drawn from, so the two cannot disagree — is what makes the small ones reachable without one. dataKey is the leaf field the area is measured from, and it is the column that table prints.
| path | Value |
|---|---|
| editor.chunk.js | 412 |
| framework.js | 268 |
| charts.chunk.js | 96 |
| markdown.js | 74 |
| highlight.js | 58 |
| icons.js | 41 |
| router.js | 33 |
| forms.js | 28 |
| dates.js | 24 |
| toast.js | 19 |
| dialog.js | 17 |
| popover.js | 15 |
| tooltip.js | 12 |
| menu.js | 11 |
| tabs.js | 9 |
| avatar.js | 7 |
| badge.js | 5 |
| kbd.js | 4 |
| spinner.js | 3 |
| clsx.js | 2 |
Types
export type TreemapVariant = 'ramp' | 'nested'
export type TreemapExtras = Omit<ComponentProps<typeof RechartsTreemap>, 'data' | 'dataKey'>Accessibility
- title is required. The table view lists the LEAVES with the path that names them: a nested tree read row by row is not something anyone can follow.
- Area is the encoding, so the data must be non-negative and must sum to something the reader recognises as the whole.
- The gap between tiles is a surface-coloured stroke rather than a smaller rect — a treemap whose parts do not touch stops reading as a partition.