Heatmap
A matrix of magnitudes — hour against weekday, endpoint against day, anything with two labelled axes and one number in each cell.
Colour is the only channel a heatmap has, so it uses a sequential ramp: one hue mixed toward the muted surface, light for little and saturated for a lot. Never a rainbow, which has no order in it. The cells fade in in a diagonal wave as the grid mounts. Hover or arrow onto one for its exact value; the grid is one tab stop and the arrows move in two dimensions. Every cell is also a row in a visually-hidden table, which is what makes the data readable when the colour is not. The table sits inside a clipped box: a table grows to fit its content whatever width it is given, so on its own it would widen a phone page.
Charts · keyboard contract
<script lang="ts">
import { Heatmap } from '@l4st/driftwood';
</script>
| Light | Dark |
|---|---|
![]() |
![]() |
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
rows required |
string[] |
— | Row labels, top to bottom. |
columns required |
string[] |
— | Column labels, left to right. |
values required |
(number | null)[][] |
— | values[row][column]. null is "no data" and renders as an empty cell. |
color |
string |
'var(--chart-1)' |
The hue the ramp is built from. One hue, always — mixed toward --muted. |
max |
number |
— | Force the top of the ramp. Defaults to the largest value present. |
format |
(value: number) => string |
compact |
Formats the tooltip, the scale and the table. |
cellHeight |
number |
24 |
Cell height in pixels; the width follows the container. |
labelEvery |
number |
— | Show every nth column label. Defaults to as many as fit. |
rowsLabel |
string |
'Row' |
Heads the row-label column of the screen-reader table — what the rows are ('Day', 'Volume'). |
aria-label required |
string |
— | Names the grid, and captions the table. Required. |
class |
string |
— | Merged with the component's own classes, last — so yours win. |
Keyboard
| Key | Does |
|---|---|
| ← / → | move along a row |
| ↑ / ↓ | move between rows |
| Home / End | first / last cell in the row |
| Escape | clear the highlight |
Example
The markup behind the screenshot above, lifted from src/routes/shots/ — so it
compiles, and it is exactly what produced the image.
<Heatmap
rows={['volume1', 'volume2', 'volume3', 'volume4']}
columns={['00', '03', '06', '09', '12', '15', '18', '21']}
values={[
[2, 1, 0, 8, 14, 19, 22, 9],
[3, 1, 1, 9, 17, 24, 20, 7],
[1, 0, 2, 11, 21, 26, 18, 6],
[4, 2, 1, 7, 12, 16, 25, 12]
]}
rowsLabel="Volume"
aria-label="Reads per second, by volume and hour"
/>
Notes
The ramp
Colour is the only channel a heatmap has, so it uses a sequential ramp: the
one hue in color, mixed toward --muted in proportion to the value. One hue,
light to dark — never a rainbow, which has no order a reader can rank, and
never a diverging pair unless the data actually has a meaningful midpoint.
The ramp starts at an 8% mix rather than 0, so a real but tiny value never
renders identically to an empty cell. null is the empty cell.
What it is for
The shape of a pattern — when the load arrives, which row is unlike the others. It is bad at exact values, which is what the tooltip and the visually-hidden table are for. If the reader needs to compare precise numbers, they want a BarChart.
Charts · LineChart · BarChart · DonutChart · ShareBar · Gauge · Sparkline · ChartLegend
driftwood
Layout
Actions
Forms
- Field
- Input
- FileInput
- FileList
- Textarea
- CodeEditor
- Combobox
- RadioGroup
- NumberInput
- InlineEdit
- Label
- Select
- MultiSelect
- DatePicker
- TagsInput
- Checkbox
- Switch
- Slider
Feedback
Charts
Overlays
Navigation
Generated from the source by pnpm wiki · repository · v0.24.0

