Calendar Pulse Heatmap React component
A year of activity in twelve dot calendars, with intensity levels, day-by-day replay, hover ripples and full keyboard navigation.
About the Calendar Pulse Heatmap component
Calendar Pulse Heatmap lays out an entire year as twelve miniature calendars. Dot size and opacity represent relative activity. A replay sweeps through the year, and hovering a day sends a restrained ripple through its month.
When to use it
Explore daily sessions, commits or completed work across a full year.
See seasonal patterns and identify unusually active days.
Installation
Add the Calendar Pulse Heatmap component to your project with the shadcn CLI. It lands in components/calendar-pulse-heatmap.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/calendar-pulse-heatmapProps
<CalendarPulseHeatmap /> accepts 9 props, all optional. It also accepts the usual <section> attributes, like className, style, id and aria-*, and passes them to its root element.
| Prop | Type | Default |
|---|---|---|
| theme | "dark" | "light" | "dark" |
| title | string | "Year in sessions" |
| subtitle | string | "One dot per day. Point at a day, or replay the whole year." |
| data Days with activity. Days left out count as zero. | { date: string; value: number }[] | — |
| year The calendar year on show. | number | YEAR |
| color Colour of the busiest days. | string | — |
| replaySeconds Seconds a replay of the year takes. | number | 4 |
| unit Words after the value in the readout. | [singular: string, plural: string] | ["session", "sessions"] |
| formatValue | (value: number) => string | FORMAT |
- theme"dark" | "light"Default: "dark"
- titlestringDefault: "Year in sessions"
- subtitlestringDefault: "One dot per day. Point at a day, or replay the whole year."
- data
Days with activity. Days left out count as zero.
{ date: string; value: number }[] - year
The calendar year on show.
numberDefault: YEAR - color
Colour of the busiest days.
string - replaySeconds
Seconds a replay of the year takes.
numberDefault: 4 - unit
Words after the value in the readout.
[singular: string, plural: string]Default: ["session", "sessions"] - formatValue(value: number) => stringDefault: FORMAT
Calendar Pulse Heatmap FAQ
- How are dates and intensity handled?
- Dates use YYYY-MM-DD in UTC, with Monday-first month grids and leap-year support. Missing dates count as zero; duplicate dates are summed. Invalid, negative and out-of-year entries are ignored. Positive values are divided into four relative intensity levels.
- How does keyboard navigation work?
- Tab enters the calendar on a day. Left/right move one day, up/down move a week and Home/End move to the first/last day of the year. Focus announces the date and value. Replay starts only on request, and reduced motion skips the sweep.