Calendar Heatmap
Blocks & SlicesA GitHub-style contributions heatmap, hand-rolled as SVG with no charting deps: weeks-as-columns day-grid colored by a 5-bucket violet intensity ramp, month/weekday labels, and a hover- or arrow-key-driven tooltip announced via aria-live. Cells pop in with a diagonal (col+row) stagger that is dropped under prefers-reduced-motion, where every cell renders fully visible.
Inspired by Watermelon UI — activity heatmap — independently built, not affiliated. Attribution policy
Contributions
662contributions
Mar 15, 2026
Jul 14, 2026
Jul 14, 2026
LessMore
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/calendar-heatmap.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/calendar-heatmap.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div className="w-full max-w-[560px]">
<CalendarHeatmap
weeks={18}
endDate="2026-07-14"
data={Array.from({ length: 220 }, (_, i) => {
const iso = new Date(Date.UTC(2026, 0, 1) + i * 86400000)
.toISOString()
.slice(0, 10);
const seed = (i * 1103515245 + 12345) >>> 8;
return { date: iso, count: seed % 9 === 0 ? 0 : seed % 13 };
})}
/>
</div>Props
CalendarHeatmapProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">
| Prop | Type | Default | Description |
|---|---|---|---|
| data | CalendarHeatmapDatum[] | — | Per-day activity. Days absent from the list render as level 0 (empty). |
| weeks | number | 26 | Number of week columns to show (clamped 1–53). Defaults to 26. |
| colorScale | string[] | — | Exactly 5 colors, empty → most-active. Falls back to the violet ramp. |
| endDate | string | DEFAULT_END_DATE | Last day of the grid, `YYYY-MM-DD`. Fixed constant by default so the grid is deterministic across SSR — pass your own "today" to make it live. |
| startWeekday | number | 0 | Top-row weekday, Sunday = 0 … Saturday = 6. Defaults to Sunday. |
| title | string | "Contributions" | Heading shown top-left of the card. |
npm dependencies
- lucide-react