A heatmap by two axes, weekday by hour out of the box: one shaded square per slot on the heatmap family's scale, with thresholds from the data's quantiles or your own. Weekday names and hours come from Intl in any locale, the week starts on Sunday or Monday, hours read in 12 or 24 hour style, and hour labels thin out as the grid narrows. Hovering or focusing a slot lifts it, dims everything outside its row and column into a soft crosshair and shows a tooltip; the grid is one tab stop with arrow keys, the busiest slot is named beside a Less to More legend, and slots can be made selectable. Custom row and column labels turn it into any two-axis grid. Cells share the width and never shrink below their size; a narrow frame scrolls sideways.
The import and the props worth knowing about, in one place.
import { HeatmapGrid } from "@/components/beste/component/heatmap-grid";
// data[weekday][hour], with data[0] as Sunday
<HeatmapGrid
data={sessions}
weekStartsOn={1} // 0 Sunday (default) | 1 Monday
unit={["session", "sessions"]}
label="Listening sessions by weekday and hour"
/>
// Any two axes
<HeatmapGrid
data={[[4, 9, 2], [7, 1, 5]]}
rows={["Paris", "Lisbon"]}
columns={["Q1", "Q2", "Q3"]}
color="#10b981" // any CSS color; defaults to the primary token
onSelectedChange={(cell, value) => console.log(cell, value)}
tone="outline" // "muted" (default) | "outline" | "ghost"
size="lg" // "sm" | "default" | "lg"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Arrow keys | Move between slots; the grid is one tab stop. |
|---|---|
| Home / End | The first or last slot of the row. |
| Cmd or Ctrl + Home / End | The first or last slot of the grid. |
| Page Up / Page Down | The top or bottom of the column. |
| Enter / Space | Select the slot, when slots are selectable. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
data | number[][] | — | Values by row, then column. With the default axes, `data[0]` is Sunday and each row holds 24 hours; with `rows` and `columns` it is laid out as given. |
rows | string[] | — | Custom row labels. Replaces the weekdays and turns off `weekStartsOn`. |
columns | string[] | — | Custom column labels. Replaces the hours. |
weekStartsOn | 0 | 1 | — | 0 starts the week on Sunday, 1 on Monday. Weekday rows only. |
locale | string | — | Locale for weekday names, hours and numbers. |
hourCycle | "auto" | "12" | "24" | — | 12 or 24 hour labels. "auto" follows the locale. |
color | string | — | The scale's strongest color, any CSS color. Lighter levels are mixed from it. |
levels | number | — | Number of shades including the empty one, 3 to 9. |
thresholds | number[] | — | Lowest value of each non-empty level, ascending. Computed from quantiles when left out. |
unit | [string, string] | — | Singular and plural word for the value, used in labels, the tooltip and the peak. |
formatValue | (value: number, cell: HeatmapGridCell) => string | — | Custom text for a cell's value. |
label | string | — | Accessible name of the grid. |
showLegend | boolean | — | |
showPeak | boolean | — | Names the busiest cell beside the legend. |
selected | HeatmapGridCell | null | — | Selected cell, controlled. Cells become selectable when this or `onSelectedChange` is set. |
defaultSelected | HeatmapGridCell | null | — | |
onSelectedChange | (cell: HeatmapGridCell, value: number) => void | — | |
size | "sm" | "default" | "lg" | — | |
tone | "muted" | "outline" | "ghost" | — | |
className | string | — |