ContributionGraph
contribution-graphPlots dated activity counts in a calendar heatmap with intensity legend.
Usage
Contribution wall (one year)
Week column × week row + month label + color scale legend; tone="success" is the green wall of GitHub.
<ContributionGraph
data={commits} // [{ date: "2026-07-30", count: 3 }, ...]
days={365}
tone="success"
showLegend
/>Activity bar (single line)
layout="strip" Put the most recent N days into a line and insert them to the right of the card title as an activity summary.
<ContributionGraph layout="strip" days={30} data={events} tone="danger" />Weekday label · Counts starting on Monday · Drill-down possible
showWeekdayLabels According to GitHub convention, only odd-numbered rows are marked; onDayClick makes the grid focusable button.
<ContributionGraph
data={commits}
days={120}
weekStart={1}
showWeekdayLabels
onDayClick={(d) => router.push(`/activity?date=${d.date}`)}
/>Color · Density
tone changes the color system; cellSize/gap adjusts the density, and levels adjusts the color level.
<>
<ContributionGraph data={commits} days={180} tone="chart-4" cellSize={9} gap={2} />
<ContributionGraph data={commits} days={180} tone="warning" levels={3} cellSize={14} />
</>When to use
Use ContributionGraph to show how often one subject acted each day: commits, study check-ins, publishing, alerts, or tickets.
Unlike the generic matrix in Heatmap, this component owns date geometry: it fills every calendar day, distinguishes absent reports from reported zero, groups weeks, positions month labels, and supports Sunday or Monday week starts. Both components share bucketize for consistent color levels.
Import
import { ContributionGraph, buildContributionCalendar } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| data* | ContributionDay[] | — | { date, count? }[]; duplicate days add together and omitted count means one. |
| days | number | 365 | Inclusive range length. |
| endDate | string | Date | Today | Inclusive end date. |
| weekStart | 0 | 1 | 0 | Sunday or Monday week start. |
| layout | "calendar" | "strip" | "calendar" | Week-column calendar or single recent-day row. |
| levels | number | 4 | Color levels excluding no contribution. |
| max | number | Maximum day in range | Full-scale count. |
| tone | string | "primary" | Semantic color name or arbitrary CSS color. |
| cellSize | number | 11 | Cell side length in pixels. |
| gap | number | 3 | Cell gap in pixels. |
| showMonthLabels | boolean | true | Shows month labels in calendar layout. |
| showWeekdayLabels | boolean | false | Shows alternate weekday labels in calendar layout. |
| showLegend | boolean | false | Shows the low-to-high color legend. |
| formatMonth | (isoDate: string) => string | ` ${month}\u6708 ` ("Month") | Formats month labels. |
| formatTooltip | (cell: ContributionCell) => string | Date and count | Formats each native hover title. |
| onDayClick | (cell: ContributionCell) => void | — | Enables focusable day buttons and drill-down. |
buildContributionCalendar(data, options?)
This pure date-geometry helper returns { days, weeks, monthLabels, total, max }. days contains every date and a present flag, weeks contains seven cells per column with null padding, and monthLabels contains { weekIndex, date }.
Pitfalls
- Without
onDayClick, the graph is onerole="img"summary instead of hundreds of screen-reader cells. Supplying the callback turns each day into a labeled button. - Dates align to local calendar days through
dayjs.startOf("day"); normalize server dates to the intended local day first. - A 365-day graph is about 53 columns. Built-in horizontal scrolling handles narrow cards; an outer
overflow-hiddencan clip it. - Cell radius derives from
cellSize / 4, avoiding oversized design-token radii on tiny squares. - Default runtime copy is Chinese: month labels append
"\u6708"("month"), tooltips use `${cell.date} \u00b7 ${cell.count} \u6b21("date, N times") or${cell.date} \u00b7 \u65e0\u8d21\u732e("date, no contributions"), the summary uses\u8fc7\u53bb ${calendar.days.length} \u5929\u5171 ${calendar.total} \u6b21\u8d21\u732e("N contributions over N days"), and legend endpoints are"\u5c11"("Less") and"\u591a"` ("More"). Override the formatters when English UI copy is required.
Related
Playground
<ContributionGraph
data={commits}
days={120}
/>