Skip to content

Treemap

ChartsSince 0.4.0
import { Treemap } from '@absoluteui/components/treemap';
import '@absoluteui/components/treemap/style.css';

Using Angular? See Treemap for Angular.

An accessible SVG treemap for hierarchical part-to-whole data: rectangles laid out with the squarified algorithm (area proportional to value). It provides:

  • one level at a time, tiles sorted by value (largest first); groups default to the sum of their children;
  • drill-down: a group tile opens with a click or Enter/Space; Backspace and a breadcrumb (nav “Treemap path”) in the chart toolbar go back up; each change emits aui-drill and is announced (“Showing All / Engineering”);
  • keyboard-reachable tiles in size order (one tab stop, arrow keys) with a tooltip on focus and hover;
  • printed label and value in tiles large enough to hold them (tileLabels);
  • textures (with patterns) and labels as non-color cues (WCAG 1.4.1);
  • a generated summary and a data table of the whole hierarchy.

The layout function is exported too: squarify(values, box). Nothing animates.

  • Part-to-whole breakdowns with many items or a hierarchy (budgets, disk usage, portfolio composition).
  • Showing which items dominate a total when a pie would have too many slices.
  • Precise comparison of values: use Bar Chart (areas compare poorly).
  • Few parts of one total: use Pie Chart or Bar Chart.
  • Data with negative values (not plotted).

Hierarchical budget with drill-down and the aui-drill event

Section titled “Hierarchical budget with drill-down and the aui-drill event”
import { Treemap, type TreemapDrillDetail, type TreemapNode } from '@absoluteui/components/treemap';
const data: TreemapNode[] = [
{ id: 'eng', label: 'Engineering', children: [{ id: 'web', label: 'Web', value: 30 }, { id: 'api', label: 'API', value: 20 }] },
{ id: 'ops', label: 'Operations', value: 25 },
{ id: 'people', label: 'People', value: 25 },
];
const host = document.createElement('div');
document.body.append(host);
const chart = Treemap.create(host, { label: 'Budget', data, valueFormat: { style: 'currency', currency: 'EUR', notation: 'compact' } });
host.addEventListener('aui-drill', (event) => {
const { path } = (event as CustomEvent<TreemapDrillDetail>).detail;
host.dataset.path = path.join('/');
});
chart.drillTo('eng');

Flat treemap without drill-down, exported as PNG

Section titled “Flat treemap without drill-down, exported as PNG”
import { Treemap } from '@absoluteui/components/treemap';
import { downloadChart } from '@absoluteui/components/chart-export';
const host = document.querySelector<HTMLElement>('#disk');
const button = document.querySelector<HTMLButtonElement>('#export');
if (host && button) {
const chart = Treemap.create(host, {
label: 'Disk usage',
data: [
{ id: 'video', label: 'Video', value: 420 },
{ id: 'photos', label: 'Photos', value: 180 },
{ id: 'apps', label: 'Apps', value: 95 },
{ id: 'docs', label: 'Documents', value: 30, color: 6 },
],
drillDown: false,
valueFormat: { style: 'unit', unit: 'gigabyte' },
height: 240,
});
button.addEventListener('click', () => {
void downloadChart(chart, { format: 'png', fileName: 'disk-usage' });
});
}
import { Treemap, type TreemapDrillDetail } from '@absoluteui/components/treemap';
import '@absoluteui/components/treemap/style.css';
const host = document.querySelector<HTMLElement>('#portfolio');
if (host) {
Treemap.create(host, {
label: 'Portfolio',
rootLabel: 'All assets',
data: [
{ id: 'equity', label: 'Equity', children: [{ id: 'us', label: 'US', value: 40 }, { id: 'intl', label: 'International', value: 20 }] },
{ id: 'bonds', label: 'Bonds', value: 30 },
{ id: 'cash', label: 'Cash', value: 10 },
],
formatValue: (v) => `${String(v)}%`,
});
host.addEventListener('aui-drill', (event) => {
host.dataset.level = (event as CustomEvent<TreemapDrillDetail>).detail.id ?? 'top';
});
}
import { Treemap } from '@absoluteui/components/treemap';
const host = document.createElement('div');
document.body.append(host);
Treemap.create(host, {
label: 'Budget',
data: [
{ id: 'eng', label: 'Engineering', children: [{ id: 'web', label: 'Web', value: 30 }, { id: 'api', label: 'API', value: 20 }] },
{ id: 'ops', label: 'Operations', value: 25 },
{ id: 'hr', label: 'People', value: 25 },
],
});
<div class="aui-chart aui-treemap [aui-chart--patterns]">
<div class="aui-chart__header">
title, description
<div class="aui-chart__toolbar"> (below the top level)
<nav class="aui-treemap__path" aria-label="Treemap path">
<ol class="aui-treemap__path-list">
<li class="aui-treemap__path-item"><button class="aui-treemap__path-button">All</button></li>
<li class="aui-treemap__path-item"><span aria-current="location">Engineering</span></li>
</ol>
</nav>
</div>
</div>
<div class="aui-chart__body">
<svg class="aui-chart__svg" role="group" aria-roledescription="treemap" aria-labelledby="T" aria-describedby="S">
<g class="aui-treemap__tiles">
<g class="aui-treemap__tile-group aui-chart__series--c1">
<rect class="aui-treemap__tile [aui-treemap__tile--group] aui-chart__mark" role="img" aria-label="Engineering: 50 (50%), 2 items" tabindex="0"/>
<rect class="aui-chart__pattern" aria-hidden="true"/>
</g>
</g>
<g class="aui-treemap__labels" aria-hidden="true">Engineering >, 50</g>
</svg>
<div class="aui-chart__tooltip" aria-hidden="true" hidden/>
</div>
<p class="aui-chart__summary" hidden/> <div class="aui-chart__data">Show data table, table</div>
</div>
Treemap.create(host: HTMLElement, options: TreemapOptions): Treemap

Global configuration key: treemap (see Configuration).

Option Type Default Description
label string Chart title: visible text and the accessible name of the plot (aria-labelledby); also the data table caption. Required.
hideLabel boolean false Visually hide the title; it stays the accessible name.
description string Visible description below the title, also referenced by aria-describedby (text only).
summary string Replaces the generated accessible summary (shown path, item count, total, three largest items).
valueFormat Intl.NumberFormatOptions Number format for values in tile labels, tooltips, the data table, and the summary (percentages use a percent format).
formatValue (value: number) => string Custom value text; overrides valueFormat everywhere.
hiddenSeries readonly string[] Shared chart option; a treemap has no series, so it has no effect.
data readonly TreemapNode[] Top-level nodes: { id (unique across the tree), label, value?: number | null, children?: TreemapNode[], color?: 1-8 }. Groups default to the sum of their children (a positive own value takes precedence). Zero, negative, and missing values are not plotted. At most 32 levels of nesting. Required.
root string | null null Id of the group to show (drill-down state); null shows the top level. An unknown id or a leaf falls back to the top level. Setting it through update() emits no event.
drillDown boolean true Allow opening groups by click and Enter/Space and going up with Backspace and the breadcrumb. false: groups are plain tiles and no breadcrumb is shown (drillTo() still works).
rootLabel string "All" Name of the top level in the breadcrumb and the “Showing …” text (default: localized “All”).
legend 'auto' | 'show' | 'hide' "auto" Shared chart option; a treemap labels its tiles directly and never shows a legend, so it has no effect. Globally configurable.
dataTable 'toggle' | 'visible' | 'hidden' | 'none' "toggle" Data table of the whole hierarchy (name path, value, share of parent): behind a Show data table button (built on first open), always visible, visually hidden (screen readers only), or none. Globally configurable.
tooltip boolean true Tooltip on pointer hover and keyboard focus (label, value, share). Globally configurable.
patterns boolean false Texture fills on tiles (by position in the shown level) so neighbors never differ by color alone (always on in forced colors). Globally configurable.
height number 300 Plot height in CSS px (integer 120-2000); the width follows the container. Globally configurable.
tileLabels boolean true Print the label (groups that open end with “>”) and the value inside tiles that are large enough. Globally configurable.
locale string "en-US" Number and message locale. Globally configurable. Inherited from common configuration.
direction 'ltr' | 'rtl' "ltr" rtl mirrors the layout (largest tile at the top right), right-aligns tile labels, and swaps ArrowLeft/ArrowRight. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement The host element.
element SVGSVGElement The plot (svg role=“group”), named by the title and described by the summary.
summary string The generated (or custom) accessible summary.
root string | null Id of the shown group (null: top level).
path string[] Ids from the top level to the shown group (empty at the top level).
hiddenSeries string[] Shared chart property; always empty for a treemap.
Method Description
drillTo(id: string | null): void Show the group id (null: top level). Ignored for leaves, unknown ids, and the current group. Emits aui-drill and announces “Showing {path}” politely; when focus was in the chart it moves to the largest tile (going down) or the group you came from (going up).
update(options: Partial<TreemapOptions>): void Merge, validate, and re-render. Invalid options throw and keep the previous state. A root in the options replaces the shown group (no event).
setSeriesVisible(id: string, visible: boolean): void Shared chart method; a treemap has no series, so it only re-renders.
destroy(): void Remove rendering, host classes, listeners, the resize observer, and the configuration subscription.
Event Detail Bubbles Cancelable Description
aui-drill { id: string | null; path: string[] } Yes No The shown group changed through a tile (click, Enter/Space), Backspace, the breadcrumb, or drillTo(). id: the shown group (null: top level); path: ids from the top level. Not emitted for update({ root }).

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-chart Host (shared chart chrome).
aui-treemap Host modifier for this chart type.
aui-chart--patterns patterns option on: tile textures shown.
aui-chart__header / __title / __title--hidden / __description / __toolbar Title, description, and the toolbar that holds the breadcrumb.
aui-treemap__path / __path-list / __path-item / __path-button Breadcrumb (nav “Treemap path”): ancestor buttons and the current level (aria-current=“location”).
aui-chart__body / __svg / __layer Plot container (height from –aui-chart-height), SVG, and drawing layer.
aui-chart__series--c1 ... --c8 Palette slot classes; set –aui-chart-color from color-chart-<n>.
aui-chart__pattern / aui-chart__pattern-tile Texture overlays.
aui-treemap__tiles / __tile-group / __tile / __tile--group Tile layer, per-tile group, focusable tile (also aui-chart__mark), and tiles that open (pointer cursor).
aui-treemap__labels / __label / __value aria-hidden printed labels and values (also aui-chart__value-label).
aui-chart__mark / __mark--active / __mark--hover Focusable tile and its states (thicker color-text outline).
aui-chart__tooltip / __tooltip-title / __tooltip-rows / __tooltip-row / __tooltip-label / __tooltip-value Tooltip (aria-hidden; the focused tile carries the same text).
aui-chart__empty Empty state text (No data).
aui-chart__summary Hidden summary referenced by aria-describedby.
aui-chart__data / __data--hidden / __table-toggle / __table-scroll / __table / __cell--numeric Data table fallback.

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-chart-1 | --aui-color-chart-2 | --aui-color-chart-3 | --aui-color-chart-4 | --aui-color-chart-5 | --aui-color-chart-6 | --aui-color-chart-7 | --aui-color-chart-8 | --aui-color-chart-axis | --aui-color-chart-grid | --aui-color-focus-ring | --aui-color-hover | --aui-color-link | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-font-weight-regular | --aui-font-weight-semibold | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-tooltip-max-width | --aui-touch-target-min

interface TreemapConfig extends ChartBaseConfig { tileLabels: boolean }
interface TreemapNode {
id: string;
label: string;
value?: number | null;
children?: readonly TreemapNode[];
color?: ChartColor;
}
interface TreemapOptions extends ChartCommonOptions, Partial<TreemapConfig> {
data: readonly TreemapNode[];
root?: string | null;
drillDown?: boolean;
rootLabel?: string;
}
interface TreemapDrillDetail { id: string | null; path: string[] }
function squarify(values: readonly number[], box: Readonly<{ x: number; y: number; w: number; h: number }>): { x: number; y: number; w: number; h: number }[];

Pattern: SVG treemap as a named, described group (role=“group” with aria-roledescription “treemap”) of role=“img” tiles in size order with roving focus; one level shown at a time with drill-down (Enter/Space, click), Backspace and a breadcrumb (nav “Treemap path”) to go up, a polite announcement of the shown level, and a data table of the whole hierarchy.

Key Context Action
ArrowRight / ArrowDown Tile focused Next tile in size order (largest first); ArrowLeft/ArrowRight are swapped in RTL.
ArrowLeft / ArrowUp Tile focused Previous tile.
Home / End Tile focused Largest / smallest tile.
PageUp / PageDown Tile focused Ten tiles back / forward.
Enter / Space Group tile focused (drillDown on) Opens the group; focus moves to its largest tile. Ignored on leaf tiles.
Backspace Tile focused below the top level (drillDown on) Goes up one level; focus moves to the group you came from.
Enter / Space Breadcrumb button Shows that level (native button); focus moves into the tiles.
Escape Tooltip visible Hides the tooltip without moving focus (WCAG 1.4.13); it returns on the next move.
Tab / Shift+Tab Any Breadcrumb buttons (below the top level), then one tab stop for the plot (the active tile), then the Show data table button and table region.
Element Role
svg.aui-chart__svg group with aria-roledescription “treemap” (localized), named by the title
tiles (rect.aui-treemap__tile) img with an aria-label: label, value, share of the shown level, and the item count for groups
breadcrumb (nav.aui-treemap__path) navigation named “Treemap path” with an ordered list: ancestor buttons, then the current level (aria-current=“location”); shown only below the top level
data table table (native) with caption, column headers (Name, Value, Share of parent), and row headers (the name path); wide tables scroll in a focusable region
printed labels, textures, tooltip aria-hidden (decorative duplicates of the accessible data)
Attribute Element Value
aria-labelledby svg id of the visible (or visually hidden) title
aria-describedby svg description id (when provided) and the generated summary id
aria-roledescription svg Localized “treemap”
aria-label each tile Localized “{label}: {value} ({percent})”, groups “{label}: {value} ({percent}), {count} items”, for example “Engineering: 50 (50%), 2 items”
tabindex active tile 0 on exactly one tile (roving); other tiles have none
aria-label breadcrumb nav Localized “Treemap path”
aria-current current breadcrumb item location
live region (polite) document “Showing {path}” after each drill, for example “Showing All / Engineering”
aria-expanded / aria-controls Show data table button Table open state and the table region id

Roving focus over the tiles of the shown level in size order. Drilling down moves focus to the largest tile; going up (Backspace, breadcrumb, drillTo) moves it to the group you came from, when focus was in the chart. Re-renders (resize, update) keep focus on the same tile.

Criterion Level Note
1.1.1 Non-text Content A
1.3.1 Info and Relationships A
1.4.1 Use of Color A
1.4.3 Contrast (Minimum) AA
1.4.10 Reflow AA
1.4.11 Non-text Contrast AA
1.4.13 Content on Hover or Focus AA
2.1.1 Keyboard A
2.4.3 Focus Order A
2.4.7 Focus Visible AA
4.1.2 Name, Role, Value A
4.1.3 Status Messages AA

Automated test results: Accessibility and compliance.

  • The generated summary names the shown path (below the top level), the item count, the total, and the three largest items with their shares, for example “Showing All / Engineering. treemap, 2 items, total 50. Largest: Web (60%) and API (40%).”
  • Tiles are keyboard-reachable in size order (largest first), matching the squarified layout, which places large tiles first.
  • Tiles are separated by a surface-colored gap, so neighbors need no mutual contrast; textures (patterns) and printed labels are the non-color cues.
  • The data table lists the whole hierarchy (not only the shown level), so every value is reachable without drilling.
  • Forced colors: tiles use CanvasText with Canvas separators and textures; focus uses Highlight; breadcrumb buttons use LinkText.
  • No animation.
  • Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
  • aria-roledescription support varies; screen readers without it announce “group”.
  • Whether a tile opens is conveyed by its item count in the accessible name, not by a role; Backspace is not discoverable without documentation (the breadcrumb is the visible alternative).

top level, drilled into a group (breadcrumb shown), drill-down off, empty (“No data”: no positive values), tile focused (tooltip), tile hovered, table open.

From Trigger To
any level click or Enter/Space on a group tile that group; focus on its largest tile; aui-drill; “Showing …” announced
below the top level Backspace on a tile parent level; focus on the group you came from; aui-drill
below the top level breadcrumb button that level; aui-drill
any drillTo(id) that level; aui-drill
any update({ root }) that level; no event
tooltip visible Escape tooltip hidden
  • Tiles are reachable in size order (largest first). Drilling down focuses the largest tile of the group; going up focuses the group you came from, so users never lose their place.
  • The summary names the shown path, item count, total, and the three largest items: “Showing All / Engineering. treemap, 2 items, total 50. Largest: Web (60%) and API (40%).”
  • The data table lists the whole hierarchy with name paths (“Engineering / Web”), so every value is reachable without drilling.
  • Tiles are separated by a color-surface gap; textures and printed labels are the non-color cues.
  • Openable tiles are identified by their item count in the accessible name and “>” in the printed label; Backspace is not discoverable on its own, so the breadcrumb is the visible way back.
  • Forced colors: tiles use CanvasText with Canvas gaps and textures; focus uses Highlight; breadcrumb buttons LinkText.
  • No animation. Manual screen-reader verification is pending.

The width follows the container (ResizeObserver); the height is height; the layout is recomputed on resize. Labels appear in tiles at least 3em wide and 1.6em tall (values from 3em tall) and are truncated to fit. The breadcrumb wraps; its buttons meet the minimum touch target height. Reflows at 320 CSS px.

direction: 'rtl' mirrors the layout horizontally (largest tile at the top right), anchors tile labels at the right, and swaps ArrowLeft/ArrowRight. The breadcrumb, tooltip, and table follow the document direction.

Tiles use color-chart-1..8 by palette slot (position in the shown level, or color); each meets 3:1 against surfaces in all shipped themes. Printed labels use color-text with a color-surface halo.

configureAbsoluteUI({ components: { treemap: { tileLabels: false, dataTable: 'visible' } } });

Changes apply to existing instances immediately.

Instance options override global and theme defaults. All options are dynamic.

None. The group marker “>” is text in the printed label.

All text uses textContent; SVG uses createElementNS; colors are classes. No innerHTML or style attributes.

No persistence, network access, or telemetry.

Budget: Treemap.create with 500 leaves < 60 ms in headless Chromium (e2e performance test), including the first render. Only the shown level is drawn; the data table is built lazily.

Hundreds of leaves in total; keep each level to a few dozen items so tiles stay large enough to label and target.

  • Zero, negative, and missing values are not plotted (and not listed in the table); groups whose children are all unplotted become leaves (or disappear).
  • A group’s own positive value replaces the sum of its children.
  • No positive values at all: “No data”.
  • root that no longer exists (or became a leaf) after update(): the top level is shown.
  • Tiny tiles get no printed label; the tooltip, accessible name, and table still show their values.
Code Category Cause
TREEMAP_OPTIONS configuration Missing label; data not an array; node ids not unique or empty; non-string labels; non-numeric values; invalid color or children; more than 32 levels; invalid root, drillDown, rootLabel, or formatters.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid or unknown configuration.

A failed construction leaves the host untouched.

  • One level is drawn at a time; grandchildren are not shown nested.
  • Tiles are always sorted by value.
  • Manual screen-reader verification is pending.
  • Nested multi-level rendering, sunburst and icicle layouts.
  • Selection and zoom animation.