Catalog · Charts
Heat map
Shows how much in each cell of a grid by colour and by figure, from a native table; a calendar is one.
Fits best: app — a page that shows where a grid is high or low: a week by hours, a month of days
Example
Parcels in each part of the day, for the five working days.
| Mon | Tue | Wed | Thu | Fri | |
|---|---|---|---|---|---|
| Morning | 120 | 240 | 360 | 480 | 600 |
| Afternoon | 0 | 60 | 300 | 180 | 540 |
| Evening | 30 | 90 | 150 | 270 | 420 |
Known issues
None known.
Code
Copy the markup
import "@luz-ds/catalog/components/heat-map.css";
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/heat-map.min.css" integrity="sha384-DJgfU9rFnD5GNimPOCLjdOuNzoYZICrPETuLVH/pOo2F3LcYvJLCAPq85abuQpaw" crossorigin="anonymous">
A stylesheet of @luz-ds/catalog: link components/heat-map.css after luz.css.
<table class="luz-heat-map">
<caption>Parcels per part of the day, this week. The stronger the colour, the more parcels.</caption>
<thead>
<tr><td></td><th scope="col">Mon</th><th scope="col">Tue</th><th scope="col">Wed</th></tr>
</thead>
<tbody>
<tr><th scope="row">Morning</th><td style="--v: .2">120</td><td style="--v: .4">240</td><td style="--v: .6">360</td></tr>
<tr><th scope="row">Afternoon</th><td style="--v: 0">0</td><td style="--v: .1">60</td><td style="--v: .5">300</td></tr>
</tbody>
</table>
Variants and options
| Option | Effect |
|---|---|
--v | On each cell, from 0 to 1: its value over the strongest value of the whole table |
--luz-heat-map-color | Another chart colour for a table or a cell, such as var(--luz-chart-2) |
How it works
A table with a head row of names and a name at the start of each row. Each cell is its figure in text, with a swatch above it that mixes --luz-chart-1 into --luz-chart-track in proportion to --v: the track at 0, the series at 1. The figure stays on the surface in the text colour, so it reads whatever the value.
Work out --v from your data: the value divided by the strongest value of the table, the same for every cell. A calendar is a heat map with the days of the week as columns and the weeks as rows. The inline style sets only --v; with a strict style-src, set it in a rule of your own.
The corner cell of the head row is an empty td. Keep to a handful of columns: with more than six, put the table in a luz-table-wrap.
Without JavaScript
It needs none. Without the stylesheet it reads as a table of figures.
Keyboard and ARIA
Nothing takes focus. A table keeps its roles, so a screen reader reads each figure with its row and column names. The caption names the table and says which way is more.
The swatch carries no text and no name: the figure is the value.
Contrast and focus are in the Design tab.
Design
When to use
Use it to see where the high and low values of a grid are: a week by hours, a month of days, a team by quarter.
When not to use
Do not use it for a few values (use a bar list or a column chart) or when the exact values matter more than the pattern (use a table).
Do and don't
--v from the strongest value of the whole table, so one colour always means the same figure.Writing the content
Say in the caption what the grid counts and which way is more. The colour is lighter for more in dark mode and darker in light mode, so write “the stronger the colour” and not “the darker”. The data and the labels are yours: the component only draws them.
Contrast and focus
The swatch is a chart colour on the surface; the empty one is the track, quiet on purpose, because the figure carries the value.
| Part | Colour on background | Light | Dark | High contrast | Needs |
|---|---|---|---|---|---|
Strongest swatch on the page | --luz-chart-1 on --luz-surface-page | 5.6:1 | 7.7:1 | 14.1:1 | 3:1 |
Strongest swatch against the empty one | --luz-chart-1 on --luz-chart-track | 3.4:1 | 3.8:1 | 6.8:1 | 2:1 |
Empty swatch on the page | --luz-chart-track on --luz-surface-page | 1.6:1 | 2.0:1 | 2.0:1 | 1.5:1 |
Figure | --luz-text-primary on --luz-surface-page | 15.8:1 | 15.1:1 | 21.0:1 | 4.5:1 |
Name | --luz-text-secondary on --luz-surface-page | 6.2:1 | 7.5:1 | 19.3:1 | 4.5:1 |
Measured from the token values of each mode, rounded down. Needs is the WCAG 2.2 AA minimum: 4.5:1 for text, 3:1 for focus rings, borders and icons; a quiet decorative part keeps 2:1 against what it is drawn on.
- Focus: nothing takes it.
- Not colour alone: every swatch has its figure under it in text, and in forced colors the swatch is the system highlight mixed into the canvas, with an edge.
Tokens it uses
The 12 tokens that components/heat-map.css reads, by family. Each family links to its page, with the values in every mode. In Figma they are variables with the same names: see Tokens in Figma.
- Spacing and sizing
--luz-space-2xl,--luz-space-2xs,--luz-space-3xs,--luz-space-lg- Typography
--luz-font-mono,--luz-font-sans,--luz-text-sm,--luz-text-xs- Radius
--luz-radius-sm
Keyboard and ARIA are in the Code tab.