Calendar Heatmap / Contributions
Preview: 26 weeks
Contribution-style grid: one column per week, five steps of one hue, zero on the sunken surface. Day tooltips on hover, or focus + arrow keys (Left/Right a week, Up/Down a day).
Import
import { CalendarHeatmap } from '@marbleui/ui'Props
<CalendarHeatmap>
| Prop | Type | Default | Description |
|---|---|---|---|
| summary *required | string | — | |
| values *required | Record<string, number> | — | ISO date (YYYY-MM-DD) → count. |
| className | string | — | |
| end | Date | — | Last day shown (defaults to today). |
| label | (count: number, date: Date) => string | (c, d) => `${c} on ${d.toDateString()}` | |
| weeks | number | 26 |
Usage notes
Daily counts as a contribution-style grid: one column per week, one row per weekday. For two arbitrary category axes use Heatmap.
<CalendarHeatmap
weeks={26}
values={{ '2026-10-26': 4, '2026-10-27': 9, '2026-10-28': 2 }}
summary="412 contributions in the last 26 weeks, mostly on weekdays."
label={(count, date) => `${count} contributions on ${date.toLocaleDateString()}`}
/>
valuesmapsYYYY-MM-DDto a count; missing days count as zero. The grid ends atend(default today) and each column starts on Sunday.- Zero is drawn on the sunken surface; other counts fall into four steps relative to the largest count in
values, including days outside the visible range. - There is no
titleand no “Show data” table. The per-daylabeltext shows on hover, or on keyboard: Tab focuses the grid, Up/Down step a day, Left/Right a week, and a live region reads the day. Put the totals that matter insummary, or place aTablealongside. - Month names are always English. The default
labelreads like “3 on Wed Oct 28 2026”, so pass your own with units.
Example source · show· hide
import { useMemo } from 'react'
import { CalendarHeatmap } from './calendar-heatmap'
function useContributions(weeks: number) {
return useMemo(() => {
const out: Record<string, number> = {}
const d = new Date()
for (let i = 0; i < weeks * 7; i++) {
const day = new Date(d)
day.setDate(d.getDate() - i)
const wd = day.getDay()
const n = Math.max(0, Math.round((wd === 0 || wd === 6 ? 1 : 6) * Math.abs(Math.sin(i * 1.7)) + (i % 9 === 0 ? 8 : 0) - 1))
out[day.toISOString().slice(0, 10)] = n
}
return out
}, [weeks])
}
function HalfYear() {
const values = useContributions(26)
return <CalendarHeatmap values={values} weeks={26} summary="Contributions over the last 26 weeks; most activity on weekdays." label={(c, d) => `${c} contributions on ${d.toLocaleDateString('en', { month: 'short', day: 'numeric' })}`} />
}
function Quarter() {
const values = useContributions(13)
return <CalendarHeatmap values={values} weeks={13} summary="Deploys over the last 13 weeks." label={(c) => `${c} deploys`} />
}
export const styles = { '26 weeks': HalfYear, '13 weeks': Quarter }Source: packages/ui/src/calendar-heatmap/calendar-heatmap.tsx
Catalog
- Category
- charts
- Priority
- Pro
- Primitive
- custom