ComponentAdded in v15.1

Treemap Chart

A hierarchy as nested rectangles, each with an area in proportion to its value.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrTreemapChart } from 'ngwr/charts/treemap-chart';

@Component({ imports: [WrTreemapChart] })
export class MyComponent {}

Basic

Each top-level node takes the next palette colour, and everything inside it shares it. A group without a value is the sum of its children.

<wr-treemap-chart ariaLabel="Budget by department" [data]="budget" />
budget: WrTreemapNode[] = [
  {
    label: 'Engineering',
    children: [
      { label: 'Platform', value: 420 },
      { label: 'Web', value: 310 },
      { label: 'Mobile', value: 260 },
      { label: 'QA', value: 120 },
    ],
  },
  // …
  { label: 'Legal', value: 60 },
];

Groups

Give a group a value above its children's sum and the rest of its rectangle stays empty: what the children do not account for.

<wr-treemap-chart ariaLabel="Disk usage, GB" [data]="disk" />
disk: WrTreemapNode[] = [
  // 512 GB, of which the children account for 400: the rest stays empty.
  {
    label: 'Photos',
    value: 512,
    children: [
      { label: '2025', value: 220 },
      { label: '2026', value: 180 },
    ],
  },
  { label: 'Videos', value: 380 },
  // No value: Music is the sum of its children, 125.
  {
    label: 'Music',
    children: [
      { label: 'Albums', value: 90 },
      { label: 'Podcasts', value: 35 },
    ],
  },
  { label: 'Documents', value: 64 },
];

Labels

Names go inside the tiles with room for them, a group's in a strip along its top. A long name is cut with an ellipsis, and a tile too small writes nothing. showValues and showLabels turn the text off.

<!-- Three levels deep -->
<wr-treemap-chart ariaLabel="Repository by lines of code" [data]="repo" [height]="320" />

<!-- Names only -->
<wr-treemap-chart ariaLabel="Repository by lines of code" [data]="repo" [showValues]="false" />

Number format

Values and shares follow LOCALE_ID. valueFormat writes every value: in the tiles, the tooltip and the data table. A value wider than its tile is left out of it, never cut. percentFormat writes the shares, and it takes a ratio, so 0.25 is a quarter.

<wr-treemap-chart
  ariaLabel="Budget by department"
  [data]="budget"
  [valueFormat]="usd"
  [percentFormat]="percent"
/>
dollars = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
usd = (value: number) => `${this.dollars.format(value)}K`; // $1,110K

// A ratio in, as Intl's percent style takes it: 0.25 is a quarter.
percents = new Intl.NumberFormat('en-US', { style: 'percent', minimumFractionDigits: 1 });
percent = (ratio: number) => this.percents.format(ratio);

Right to left

The layout starts at the inline-start edge, so on a right-to-left page the largest node sits at the top right.

<div dir="rtl">
  <wr-treemap-chart ariaLabel="Budget by department" [data]="budget" />
</div>

Data table

dataTable adds a table only screen readers reach: a row per node, headed by its path, with its value and its share of the whole. Nothing changes on screen.

<wr-treemap-chart ariaLabel="Budget by department" valueLabel="Budget, $K" [data]="budget" dataTable />
Budget by department
Budget, $KShare
Engineering1,11045.7%
Engineering / Platform42017.3%
Engineering / Web31012.8%
Engineering / Mobile26010.7%
Engineering / QA1204.9%
Sales77031.7%
Sales / Americas34014%
Sales / EMEA28011.5%
Sales / APAC1506.2%
Marketing30012.3%
Marketing / Brand1405.8%
Marketing / Events903.7%
Marketing / Content702.9%
Operations1907.8%
Operations / IT1104.5%
Operations / Facilities803.3%
Legal602.5%

Accessibility

PartBehaviour
DrawingOne role="img", named by ariaLabel. The tiles announce nothing.
NumbersIn the tooltip, which is pointer only, and in the table dataTable adds.
GroupsTold apart by their name and by their tiles sitting inside their own rectangle, not only by colour.
Tile edges A faint gap in the surface colour. Under prefers-contrast: more it is a line at 3:1 or more.
NamesCut with an ellipsis where a tile is narrow. The tooltip and the table carry the whole path.
ValuesNever cut: a value wider than its tile is left out. The tooltip and the table carry it whole.
Forced coloursThe tints give way to the system palette; every tile keeps an outline in the text colour.
KeyboardNo tab stop.

Drill-down

Not in this version. Every level is drawn at once and nothing zooms into a group: give a deep tree one level at a time, or split it into several charts.

API

NameDescriptionTypeDefault
dataThe nodes, top level first. A node with children is a group drawn round them, and one without is a leaf drawn at its value. Top-level nodes with no color take the palette's colours in order.readonly WrTreemapNode[][]
ariaLabelAccessible name of the drawing. The tiles carry no text a screen reader reaches, so this is where to say what the chart shows — or turn on dataTable. Falls back to treemapChart.label, which is also the data table's caption.string | nullnull
valueLabelWhat the values measure — revenue, size on disk — as the heading of the data table's value column. Falls back to treemapChart.value ("Value").string | nullnull
heightThe plot's height in px, at least 80. Its width is the container's.number280
showLabelsWrite the names inside the tiles that have room for them, a group's in a strip along its top. Off, no tile carries text and no group reserves a strip.booleantrue
showValuesWrite each value under its name, and each group's beside its name, where there is room.booleantrue
tooltipShow a tooltip for the tile under the pointer: its path from the top-level node, its value, and its share of the whole. Pointer only — the data table is where the same figures are for a keyboard or a screen reader.booleantrue
valueFormatWrites every value the chart shows: inside the tiles, in the tooltip and in the data table. null uses Intl.NumberFormat in LOCALE_ID, compact inside the tiles (1.2K). A value wider than its tile is left out of it rather than cut. Shares are percentFormat's.((value: number) => string) | nullnull
percentFormatWrites every share the chart shows, given as a RATIO — 0.25 for a quarter — the number Intl.NumberFormat's percent style takes, so one of those can be passed as it is: in the tooltip and in the data table. null uses that style in LOCALE_ID, with up to one fraction digit, and two significant digits below 1% so a sliver is not printed as 0%.((ratio: number) => string) | nullnull
dataTableRender the chart's figures as a table that only assistive technology reaches: a row per node, parents before their children in the data's order, headed by its path — Engineering / Web — with its value and its share of the whole. A node with no area is listed with an empty share, and a leaf with no value with an empty value too. The drawing is one named role="img", which hides everything inside it, so without the table the numbers are nowhere a screen reader can walk. It is rendered beside the drawing, clipped to nothing: it takes no room, draws nothing and holds no tab stop.booleanfalse

Types

interface WrTreemapNode {
  label: string;
  value?: number;
  children?: readonly WrTreemapNode[];
  color?: string;
}
NameDescriptionTypeDefault
WrTreemapNodeA leaf, or a group drawn round its children.interface—
labelrequiredTile, tooltip path and table row name.string—
valueA leaf's area. On a group, defaults to the children's sum; a larger value leaves the rest of the group empty.number—
childrenThe nodes drawn inside this one.readonly WrTreemapNode[]—
colorCSS colour for this node and everything inside it.stringpalette

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/charts/treemap-chart's own element.

VariableDefaultDeclared on
--wr-treemap-chart-active-ringvar(--wr-color-on-surface).wr-treemap-chart
--wr-treemap-chart-active-ring-width2px.wr-treemap-chart
--wr-treemap-chart-bgvar(--wr-color-surface).wr-treemap-chart
--wr-treemap-chart-font-familyvar(--wr-font-family-base).wr-treemap-chart
--wr-treemap-chart-gap1px.wr-treemap-chart
--wr-treemap-chart-gap-colorvar(--wr-color-surface).wr-treemap-chart +1 variant override
--wr-treemap-chart-group-tint14%.wr-treemap-chart
--wr-treemap-chart-header-font-weightvar(--wr-font-weight-semibold).wr-treemap-chart
--wr-treemap-chart-header-gapvar(--wr-space-xs).wr-treemap-chart
--wr-treemap-chart-label-colorvar(--wr-color-on-surface).wr-treemap-chart
--wr-treemap-chart-label-font-sizevar(--wr-text-xs).wr-treemap-chart
--wr-treemap-chart-label-font-weightvar(--wr-font-weight-medium).wr-treemap-chart
--wr-treemap-chart-label-line-heightvar(--wr-text-xs-leading).wr-treemap-chart
--wr-treemap-chart-label-padding-xvar(--wr-space-xs).wr-treemap-chart
--wr-treemap-chart-label-padding-ycalc(var(--wr-space-xs) / 2).wr-treemap-chart
--wr-treemap-chart-leaf-tint34%.wr-treemap-chart
--wr-treemap-chart-radiusvar(--wr-border-radius-sm).wr-treemap-chart
--wr-treemap-chart-value-font-weightvar(--wr-font-weight-regular).wr-treemap-chart

Dependencies

Built onPopover

See also