Skip to content

No.251 · Analytics

Calendar Heatmap

A year of daily activity, one square per day on a single-hue ramp; hover or arrow through the year to read any day exactly.

The prompt

The design brief behind this component — reuse it to regenerate, remix, or explain it.

Build a calendar heatmap of a year of daily values in SVG with no chart library: 53 Monday-first week columns of seven 12px rounded squares (3px gaps), month labels over the first week of each month and Mon/Wed/Fri row labels. Each day is shaded on a six-step single-hue sequential ramp (empty, then light to dark blue, with the dark theme re-stepped rather than inverted) by its value relative to the year's maximum. The headline is the year's total; three derived stats sit under it — busiest day, longest streak of active days, quietest weekday. Hover a day (or focus the calendar and move with the arrow keys: ±1 day vertically, ±1 week horizontally, Home/End) to outline it and read "Sat 14 Feb: 37 bookings" in a polite live line below. A Less → More legend shows the ramp. A year switch recolours the squares with a short fill transition that sweeps across the weeks (6ms per column). Monthly totals are also in a visually hidden table. The demo data is seeded and plausible: busier in winter and at weekends, quiet on Fridays, softer during Ramadan.

Notes

Interaction
Hover a day, or focus the calendar and use the arrow keys, to read exact values; switch the year above.
Motion
Year switch: fills transition 420ms, staggered 6ms per week column.
Accessibility
The calendar is a focusable role="img" with a summary and full arrow-key reading through a polite live line; monthly totals are in a visually hidden table; the legend explains the ramp. Reduced motion recolours instantly.
Responsive
Scales with its container; the calendar scrolls horizontally inside its card on narrow screens rather than shrinking squares.
On touch
Tap to highlight; the table view covers precise reading.

Featured

301 components