Activity heatmap
A React component in Beamline's Charts & data-vis category.
A calendar of daily counts, one cell per day on a sequential ramp: weeks across, weekdays down, month and weekday labels, a legend scale, hatched days that were never recorded, and a keyboard grid that reads each day's date and value.
Use it for
- Daily activity over weeks or months where rhythm, streaks and quiet days matter: deploys, active users, incidents, commits.
Not for
- Comparing exact amounts between a few days (bar-chart).
- Up/down status per day or check (tracker).
- A trend line of one daily metric (line-chart).
Anatomy
- title and description (figcaption)
- table button
- month labels (above the week columns)
- weekday labels (Mon, Wed, Fri; pinned while the grid scrolls)
- grid (rows = weekdays, columns = weeks)
- day cell
- readout (focused or hovered day, else the period summary)
- legend scale (level swatches with their ranges, hatched “Not recorded” key)
Variants
- 0: ramp: accent (fades into the surface at zero, both themes) · heat · cool (the system's data ramps)
- 1: weekStartsOn: 0 (Sunday) · 1 (Monday)
- 2: thresholds: explicit level bounds, or quarters of the busiest day
States
- loading (skeleton)
- empty (no days in the range)
- unmeasured days (absent from data or null): hatched, read “Not recorded”, never zero
- measured zero: the faint zero swatch
- focused / hovered day (ring; readout shows its date and value)
- selected day (ink ring that stands out on every ramp colour, aria-selected)
- table view (every day with its value)
- narrow widths: the grid scrolls inside its frame, opened at the latest week
- right-to-left: weeks run from the right, ← and → swap, the scroller opens at the latest week on the left
Keyboard
- Tab enters the grid on the selected day (or the latest one); one cell is in the tab order
- ↑/↓ move a day, ←/→ move a week (mirrored in right-to-left)
- Home/End go to the first/last day of the range; Page Up/Page Down move a month
- Enter or Space selects the day (onSelectedChange); Escape clears the selection
- Each cell's accessible name is its full date and value
Motion
Columns fade in once from the oldest week (one character stagger step every two weeks, about 300 ms for a year); instant under reduced motion. Hover arrives at once.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | ActivityDay[] | — | { date: "YYYY-MM-DD", value: number | null } per day. Days in the range missing from data, or null, are unmeasured (hatched). |
start / end | string | — | The range (ISO dates); the first and last day of data by default. |
format | (value: number) => string | — | How a day's value reads: "12 deploys". |
valueLabel | string | — | The value column's heading in the table view. Default "Value". |
thresholds | number[] | — | Lower bounds of levels 2…n (level 1 starts above zero). Default: quarters of the busiest day. |
ramp | "accent" | "heat" | "cool" | — | Colour scale. Default accent. |
weekStartsOn | 0 | 1 | — | First row. Default 1 (Monday). |
selected / defaultSelected / onSelectedChange | string | null | — | The chosen day (ISO date). |
locale | string | — | Month and weekday names. Default en-US, so server and client agree. |
title / hideTitle / description | string / boolean / ReactNode | — | The figure's name (a heading unless hidden) is always its accessible name. |
table | boolean | — | Offer “View as table”. Default true. |
loading | boolean | — | Skeleton of the chart's shape; keeps the frame's size. |
actions | ReactNode | — | Controls beside the legend (range, offset). |
className | string | — | Lands on the figure. |
classNames | ChartClassNames | — | Frame, tooltip and slice-list parts as applicable to this chart. |
style / ref | CSSProperties / Ref<HTMLElement> | — | The native chart figure; layout measurement refs stay internal. |
Dependencies
motion
Import
import { ActivityHeatmap } from "@/components/activity-heatmap/activity-heatmap";
Get it
Activity heatmap is part of Beamline: 190 React components and screens your coding agent (Claude Code, Codex, Cursor or any MCP client) installs into your app through Beamline's MCP server, as a ready-built package or as plain React source you can change. $49 one payment (regular $200), no subscription, a year of updates, one licence for your whole team. Get Beamline · Connect your agent
More in Charts & data-vis
- Area chart: Amounts over time as filled areas: overlapping, stacked or as shares of 100%, five fills, two strokes, five curves, a range handle; gaps for missing…
- Bar chart: Amounts by category as bars: columns or rows, grouped, stacked or as shares, reference lines, five looks (rounded, cells, trace, isometric, monospace), a…
- Composed chart: Different measures on one time axis: bars, lines and areas per series, a left and a right value axis with their own formats, and reference lines.
- Gauge: One value against a known range: a semicircle, a 270° dial or a full ring, filled or with a needle, coloured bands with their names (healthy, busy…
- Line chart: Values over time as lines: curves, point markers, dashed series for forecasts, reference lines for limits and targets, an optional zero baseline and a…
- Pie chart: A few shares of a whole as a pie or donut, with spaced slices, percent labels, a centre readout and a list of every slice with value and share; hovering…
- Radar chart: A few series compared across the same five to eight dimensions as polygons on a polygon or circle grid; hover or arrow keys pick a dimension and read…
- Radial chart: Progress of a few measures toward their targets as concentric rings, full or half circle, with a centre readout and a list of each ring's value, target…
- Ridgeline: Distributions per group as overlapping density ridges (response time by region, order size by plan): an overlap control, median and p95 readouts per row…
- Sankey chart: Flows between stages as bands whose width is the amount: sources to pages to outcomes, budgets to teams; hovering or focusing a node lights its flows and…
- Slope chart: Change between two points in time per item, by value or by rank: labels on both sides that never collide, rising and falling told by the end marker (▲ ▼)…
- Sparkline: A compact trend beside its value: point along it or focus it and use ← → to read each point; nulls are gaps. TrendLine is the bare line.
- Streamgraph: Stacked flows over time around a centre baseline, with silhouette, wiggle, expand (shares) and zero offsets: a legend that turns layers on and off, a…
- Treemap: Nested rectangles sized by value (spend by team, then service), squarified so tiles stay close to square: labels that fit or hide, hover and focus…
- Waffle chart: Units of a whole as a grid of cells by category (seats used of a plan, tickets by channel): a 10×10 grid by default, hatched cells for units whose…