webdevpuneet.com

Treemap Chart in HTML, CSS & JS — Squarified, No Library

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

CategoryCharts

Copy & paste

Source Code

<div class="tm-card">
  <div class="tm-head">
    <div class="tm-titles">
      <h3>Disk usage by folder</h3>
      <span class="tm-total" id="tmTotal"></span>
    </div>
    <div class="tm-seg" role="group" aria-label="Measure by">
      <button type="button" class="tm-seg-btn is-on" data-m="size" aria-pressed="true">Size</button>
      <button type="button" class="tm-seg-btn" data-m="files" aria-pressed="false">Files</button>
    </div>
  </div>
  <div class="tm-box" id="tmBox"></div>
  <div class="tm-detail" id="tmDetail" aria-live="polite"></div>
  <div class="tm-tip" id="tmTip" hidden></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Squarified layout
Rows grow only while the worst aspect ratio improves, so tiles stay close to square.
Animated measure switch
Size and Files re-pack the same tiles, which slide to their new positions.
Hover focus
Other tiles dim to 50% and the hovered one lifts, with a tooltip showing value and percentage.
Click-to-inspect panel
The selected folder's value, share and progress bar update below the chart.
Labels only where they fit
Names appear from 78×46px and percentages from 120px wide; small tiles use the tooltip.
Keyboard operable
Every tile is a labelled button, reachable with Tab and selected with Enter.
ResizeObserver repack
The layout recalculates whenever the box width changes, including on rotation.
Reduced-motion aware
Entrance and glide animations switch off for visitors who prefer less motion.

About this UI Snippet

Treemap — Squarified Layout, Animated Measure Switch and a Click-to-Inspect Panel

Screenshot of the Treemap snippet rendered live

A treemap fills a rectangle with tiles whose area is proportional to a value, so you can see at a glance which item dominates and how the rest compare. This version is a disk-usage chart built in plain HTML, CSS and vanilla JavaScript: it computes a squarified layout itself, lets you switch the measure between Size and Files with the tiles gliding to their new positions, dims everything but the tile you hover, and shows the selected folder's share in a detail panel underneath. There is no charting library and no canvas, so every tile is a real button.

Squarified layout, written out

squarify(list, x, y, w, h) converts each value to pixels of area, then fills the rectangle row by row. It keeps adding tiles to the current row while the worst aspect ratio in that row does not get worse, and starts a new row as soon as it would. The row is laid as a column when the free space is wide and along the top when it is tall. This is the algorithm behind D3's treemap and most disk-usage tools, and it is why the tiles stay close to square instead of turning into thin strips.

Switch the measure and the tiles move

Two buttons, Size and Files, change which number drives the area. The tiles are built once; a re-render only changes each tile's translate, width and height, and a short morph class turns on a CSS transition so they slide into the new arrangement. The same folder that dominates by size (node_modules at 1.84 GB) is also huge by file count, while Videos shrinks to a sliver because it holds only 310 files — the kind of contrast a treemap is good at showing.

Hover focus and a click-to-inspect panel

Hovering a tile dims the others to half opacity and lifts the hovered tile slightly, with a cursor-following tooltip carrying the name, value and percentage. Clicking a tile (or pressing Enter on it) selects it: a white inner ring marks it, and the panel below shows its value, its share of the total as a large percentage and a progress bar that animates when the selection changes.

Labels that fit

A tile shows its name only when it is at least 78px wide and 46px tall, and adds the percentage once it passes 120px. Smaller tiles stay clean and rely on the tooltip and the panel, so nothing is clipped.

Responsive, accessible, motion-aware

A ResizeObserver re-runs the layout whenever the box changes width, so the chart repacks on rotation or window resize. Tiles enter with a staggered scale-and-fade, and prefers-reduced-motion turns the entrance and the glide off. Because the tiles are buttons with aria-labels, the chart can be reached with Tab and operated with Enter.

Your data

Edit the DATA array: each entry takes a name, a colour and one number per measure. Add a measure by adding a key to the entries and to METRICS along with a formatter.

Step by step

How to Use

  1. 1
    Paste HTML, CSS and JSThe tiles fade in one after another, with node_modules selected and its share shown in the panel under the chart.
  2. 2
    Hover a tileThe other tiles dim, the tile lifts, and a tooltip shows its name, value and percentage.
  3. 3
    Click or press Enter on a tileIt gets a white ring and the panel shows its value, share of the total and a progress bar.
  4. 4
    Switch Size / FilesThe tiles glide to a new arrangement because the area now follows the other measure.
  5. 5
    Replace DATAGive each entry a name, a colour and a number for each measure, then add matching keys to METRICS.
  6. 6
    Change the heightEdit the .tm-box height in the CSS; the layout reads the real box size, so no JavaScript change is needed.

Real-world uses

Common Use Cases

Storage and quota screens
Show which folders eat a drive or workspace, switch to file count to find the folder with thousands of tiny files, and click one to see its exact share.
Spend breakdowns
Lay out budget categories by amount, then flip to transaction count so finance can see a category that is small in money but busy in activity.
Portfolio allocation
Size tiles by holding value and compare with a pie chart when there are only three or four positions worth showing.
Bundle and repo analysis
Map package size against file count to spot the dependency that dominates your build, with the percentage panel ready for a screenshot in a report.
Inventory by category
Fit dozens of categories in a fixed box, where a bar chart would scroll, and let staff click a tile for stock share.

Got questions?

Frequently Asked Questions

Slice-and-dice splits the rectangle in two at every step and often produces long thin strips. Squarified lays out rows and checks the worst aspect ratio before adding each tile, so shapes stay near square and are easier to compare and label. It costs a few more lines but reads much better with eight or more items.

The tiles are created once. Switching the measure re-runs the layout and sets a new translate, width and height on each existing tile, while a temporary morph class adds a 0.55s transition. Because the elements are reused rather than rebuilt, they slide between positions instead of popping in.

A label needs room or it gets clipped. A tile shows its name only when it is at least 78px wide and 46px tall, and adds the percentage past 120px. Every tile still shows its name, value and percentage in the hover tooltip, and clicking it puts the same details in the panel below.

Yes. Add a numeric key to each DATA entry, add a matching entry with a formatter to METRICS, and add a button with that key in data-m. The layout reads DATA[i][metric], so no other code changes.

Keep the data, metric and selected item in state, compute the layout from a measured width (a ResizeObserver hook in React, a ref in Vue or Angular) and render the tiles with a loop, using the translate, width and height values as inline styles. The squarify function is plain JavaScript and moves over unchanged.