Activity Heatmap
DataMITGitHub-style yearly activity contribution grid with hover tooltips.
bun add @otfdashkit/ui
Preview
Activity HeatmapData
Loading Storybook preview…
Code
@otfdashkit/uiimport { ActivityHeatmap } from '@otfdashkit/ui'
const HEATMAP_DATA = (() => {
const out: { date: string; value: number }[] = []
let seed = 42
const rng = () => { seed = (seed * 9301 + 49297) % 233280; return seed / 233280 }
const today = new Date('2026-04-29')
const start = new Date(today); start.setDate(start.getDate() - 365)
const cursor = new Date(start)
while (cursor <= today) {
const dow = cursor.getDay()
const isWeekend = dow === 0 || dow === 6
out.push({
date: `${cursor.getFullYear()}-${String(cursor.getMonth() + 1).padStart(2, '0')}-${String(cursor.getDate()).padStart(2, '0')}`,
value: Math.max(0, Math.round(rng() * (isWeekend ? 6 : 22))),
})
cursor.setDate(cursor.getDate() + 1)
}
return out
})()
export function Example() {
return (
<div className="p-4 max-w-5xl">
<ActivityHeatmap
caption="Activity"
total={1_847_392}
data={HEATMAP_DATA}
endDate={new Date('2026-04-29')}
stats={[
{ label: 'Most Active Month', value: 'March' },
{ label: 'Most Active Day', value: 'Mar 18, 2026' },
{ label: 'Longest Streak', value: '64d' },
{ label: 'Current Streak', value: '21d' },
]}
/>
</div>
)
}
Free with the SDK. This component ships in @otfdashkit/ui under the MIT license.
Props
Props declared in the ActivityHeatmap source. Inherited HTML attributes are not listed.
| Prop | Type | Default | Description |
|---|---|---|---|
| datarequired | HeatmapDay[] | Daily values for the heatmap | |
| totalrequired | string | number | The big number above the heatmap (e.g. total events) | |
| caption | string | 'Activity' | Caption above the total — e.g. "Activity" |
| cellSize | number | 11 | Cell size in px. Default 11. |
| centered | boolean | true | Center the heatmap horizontally inside its scroll container. Default true. |
| className | string | ||
| colorScale | string[] | Optional 5-step color scale. Defaults to primary opacity ramp. | |
| endDate | Date | Date the heatmap should end on. Defaults to today. | |
| filterValue | string | ||
| filters | FilterOption[] | Optional filter — renders a ToggleGroup at the top right | |
| formatTooltip | (day: HeatmapDay) => string | Tooltip formatter passed to Heatmap | |
| gap | number | 3 | Gap between cells in px. Default 3. |
| onFilterChange | (value: string) => void | ||
| stats | SummaryStat[] | 4 summary stats shown below the heatmap (e.g. Most Active Month / Day / Longest / Current Streak) | |
| weeks | number | 53 | Number of week columns. Default 53. |