Treemap — HTML CSS JS Treemap Chart (No Library)

Treemap · Charts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Area-proportional tiles
Each tile's area (not length or angle) encodes its value — the defining treemap property.
Recursive slice-and-dice
Balanced two-way splits with area-proportional allocation pack the rectangle with no gaps.
Near-square tiles
Alternating split direction by longest axis keeps tiles from degenerating into slivers.
Adaptive labels
Tiles show inline labels only when big enough; all tiles reveal details on hover.
Cursor tooltips
A following tooltip shows each tile's name and value.
Responsive re-layout
The layout recomputes from the measured width on resize.
Largest-first ordering
Sorting by value gives a stable, readable arrangement.
Data-driven & no library
Packs and draws from a DATA array in plain HTML/CSS/JS — zero dependencies.

About this UI Snippet

Treemap — Value-Proportional Tiles via Recursive Slice-and-Dice Layout

Screenshot of the Treemap snippet rendered live

A treemap shows part-to-whole composition by filling a rectangle with tiles whose *areas* are proportional to their values — ideal for disk usage, budgets, portfolios, or any hierarchy where you want to compare sizes and use space efficiently. This snippet builds a treemap in plain HTML, CSS, and vanilla JavaScript, computing the tile layout itself with a recursive slice-and-dice algorithm and rendering positioned tiles with labels and tooltips — no charting library.

Area, not length, encodes the value

Unlike a bar chart (length) or pie (angle), a treemap encodes value as *area*. The challenge is packing rectangles of given areas into a container with no gaps and reasonable aspect ratios. The snippet solves this with a recursive split: at each step it divides the items into two groups whose value-sums are as balanced as possible, allocates the container's space between them in proportion to those sums, and recurses into each half — alternating between horizontal and vertical splits based on which dimension is longer. Alternating the split direction is the key trick that keeps tiles close to square instead of degenerating into thin slivers.

A real layout algorithm in a few lines

layout(items, x, y, w, h) is the whole engine: it finds the balanced split point, computes the area ratio, and carves the rectangle along its longer axis, assigning each leaf item a final { x, y, w, h }. This is a compact cousin of the "squarified treemap" approach used by D3 and OS disk-usage tools, written out clearly so you can see exactly how rectangles get packed by value — the part that makes treemaps look hard but is just balanced recursion.

Tiles that adapt their labels

Each item becomes an absolutely-positioned div at its computed rect, coloured per series, with a white border that visually separates adjacent tiles. Labels are shown only when a tile is big enough to hold them (a size check), so small tiles stay clean instead of overflowing with clipped text — and every tile, labelled or not, reveals its name and value on hover via a cursor-following tooltip. This "label if it fits, tooltip always" rule is how real treemaps stay legible across wildly different tile sizes.

Responsive re-layout

Because the layout is computed from the container's measured width, the treemap re-runs on resize, repacking the tiles to fill whatever space it's given. Sorting items largest-first before laying out gives a stable, readable arrangement with the biggest tiles anchored consistently.

Data-driven and drop-in

Feed it any array of { name, value, color } and it packs them by area. Because it's dependency-free, it drops into any dashboard or report, and it's a clear reference for the recursive slice-and-dice layout that powers treemaps, disk-usage visualisers, and space-filling charts.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Instead of tracing the recursion by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to walk through exactly how the layout() function picks its split index with the running acc/half comparison, and why it alternates between carving along w and h based on which is bigger rather than always splitting the same way. It's a good target for optimization questions too — ask whether recomputing the entire layout from scratch on every resize event is wasteful for a large item list, and whether the resize handler should be debounced. For extending it, have it add a second level of nesting so each tile can itself contain sub-tiles, animate tiles smoothly when the underlying values change instead of snapping instantly, or add a legend that lets users click a category to isolate it. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a treemap chart in plain HTML, CSS, and vanilla JavaScript using a recursive slice-and-dice layout algorithm — no charting library, no canvas.

Requirements:
- Accept a flat array of items, each with a name, a numeric value, and a color, and sort them largest-value-first before laying out.
- Write a recursive layout(items, x, y, w, h) function that: if given a single item, assigns it the full rectangle; otherwise finds the split index where the running sum of values first reaches half the group's total, divides the items into two groups at that index, computes the area ratio between the two groups, and recurses into each with the rectangle divided along whichever axis (width or height) is currently longer, allocating space proportional to each group's value sum.
- Render each item as an absolutely positioned div at its computed x/y/w/h, colored per item, with a visible border separating adjacent tiles.
- Only render a tile's inline name and value label when the tile's computed width and height both exceed a minimum size threshold; smaller tiles must render with no label.
- Every tile, regardless of whether it shows a label, must reveal its full name and value in a cursor-following tooltip on mousemove, and hide the tooltip on mouseleave.
- Recompute the entire layout from the container's actual measured width (not a hardcoded value) whenever the window resizes.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA treemap renders, filling the box with tiles sized by each folder's disk usage.
  2. 2
    Hover a tileSee that tile's name and exact value in a tooltip; big tiles also show inline labels.
  3. 3
    Resize the windowThe treemap repacks to fill the available width.
  4. 4
    Swap in your dataReplace the DATA array with your own { name, value, color } items.
  5. 5
    Adjust the heightChange the box height (and the H constant) to make the treemap taller or shorter.
  6. 6
    Wire to an APIFetch your sizes, map them into the DATA shape, and call render().

Real-world uses

Common Use Cases

Disk and storage usage
Visualise folder or file sizes — pair with a pie chart for a simpler share view.
Budget and spend composition
Show where money goes by area alongside a bar chart for ranking.
Portfolio and asset allocation
Map holdings by weight, complementing a donut chart.
Codebase and bundle analysis
Show module or package sizes like a bundle analyzer.
Category and inventory breakdowns
Compare many categories where space efficiency matters.
Learning treemap layout
A reference for recursive slice-and-dice packing — compare with a bubble chart.

Got questions?

Frequently Asked Questions

Value is encoded as area. The layout recursively splits the items into two groups with as-balanced-as-possible value sums, divides the rectangle between them in proportion to those sums, and recurses — alternating horizontal and vertical splits depending on which side of the rectangle is longer. Each leaf item ends up with an {x, y, w, h} whose area is proportional to its value, filling the container with no gaps.

If you always split the same way, tiles become long thin slivers that are hard to compare and label. Splitting along the rectangle's longer axis each time keeps the resulting tiles closer to square, which is the readability goal behind "squarified" treemaps. It's the single detail that separates a usable treemap from an unreadable one.

A label needs enough room or it overflows and gets clipped, which looks broken. Each tile checks whether it's wide and tall enough before rendering its inline name and value; smaller tiles stay clean. Every tile — labelled or not — still shows its full name and value on hover, so no information is lost. This "label if it fits, tooltip always" approach keeps the treemap legible across very different tile sizes.

It's a compact relative. D3 implements the full squarified algorithm with tunable aspect-ratio optimisation and hierarchy nesting. This snippet uses a simpler balanced slice-and-dice that produces near-square tiles for a flat list of values, written out so the packing logic is readable. For deep hierarchies or strict aspect-ratio control you'd reach for D3; for a flat composition view, this is enough and has no dependency.

In React, hold the data in useState, compute the layout with useMemo (re-running on a measured width), and render tiles from .map() with absolute positioning; in Vue, use a computed layout with v-for; in Angular, a getter with *ngFor. The layout() algorithm is framework-agnostic — only the width measurement and rendering move into the framework.