Heatmap matrix
FreeTwo categories against each other, coloured by value. The row and column follow the pointer or arrow keys, and choosing a step of the scale isolates its cells.
pnpm dlx shadcn@latest add https://caliperui.site/r/heatmap-matrix.jsonWhen to use #
Use it for
- Weekday by hour, feature by plan, error by service.
- Spotting the busy or broken corner of a grid.
Skip it when
- Calendar days over a year; use the activity heatmap.
- Exact comparisons; colour is approximate, so keep the table.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/heatmap-matrix.json
Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above. It is built from bucketOf and HeatmapMatrix.
import { HeatmapMatrix } from "@/components/ui/heatmap-matrix" const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; const hours = Array.from({ length: 12 }, (_, i) => `${String(i * 2).padStart(2, "0")}`); const busy = days.map((_, d) => hours.map((_, h) => (d === 2 && h === 7 ? undefined : Math.round((d < 5 ? 40 : 12) * Math.max(0.1, Math.sin(((h - 2) / 11) * Math.PI)) + ((d * 7 + h * 3) % 9))))); export function HeatmapMatrixDemo() { return <HeatmapMatrix label="Support tickets by weekday and hour (UTC)" rows={days} columns={hours} values={busy} unit=" tickets" className="w-full" />; }
API reference #
bucketOf
component
No props of its own; it accepts the native props of its root element.
HeatmapMatrix
component
Accessibility #
It exposes grid, row, columnheader, rowheader, gridcell and group semantics, with aria-label, aria-busy and aria-pressed kept in step with state.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.