ContributionGrid
Every example on this page is live, drawn by the library's Storybook, where you can also change its props and see the result.
A year of activity, one small rounded square per day, the way GitHub shows a person's contributions: a column for each week, seven days down it, and each square shaded by how busy its day was. Use it for commits, workouts, habits, reading streaks or anything else counted per day.
The busiest quarter of the days with any activity is drawn in full ink and each quarter below it a lighter tint; a day with nothing on it is a faint square. The shading follows the spread of the counts, so a quiet year and a busy one both use the whole range.
The grid scales to fit its box like a picture, squares, gaps and month names together, and keeps its shape. It fills the width it is given and is as tall as that makes it, or pass height="100%" to fit it inside a box of fixed size, centered.
Import
import { ContributionGrid } from "~lib/charts/contribution-grid";
Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
data | { date: Date | string | number; value: number }[] | Yes | N/A | The count for each day. Values given for the same day add up |
startDate | Date | string | number | No | First day given | The first day to show |
endDate | Date | string | number | No | Last day given | The last day to show |
bands | number | No | 1 | Cut the run into this many rows of weeks (columns, with direction="column") |
direction | "row" | "column" | No | "row" | Weeks side by side across the box, or one under another down it |
firstDayOfWeek | "sunday" | "monday" | No | "sunday" | The day each week starts on |
months | boolean | No | true | Name each month over the week it starts in, where there is room |
timeZone | string | No | Frame time zone | Time zone a Date or timestamp falls on its day in, such as "Europe/London" |
locale | string | No | Frame language | Language of the month names, such as "fr-FR" |
width | number | string | No | "100%" | Width, in pixels or any CSS length |
height | number | string | No | "auto" | Height; by default as tall as the width makes it |
Each day's date can be:
- a date written as
"2026-10-05", which always shows as that day, wherever the frame is - a
Date, a timestamp string or milliseconds since 1970, which shows on the day it falls on intimeZone
Days between startDate and endDate with no entry are drawn as quiet days. Every square is shaded against all of data, not only the days shown, so two grids that split one year between them shade alike.
Fitting a year in a smaller box
A year is 53 weeks across, so in a square or a narrow box its squares come out tiny. bands cuts the year into several rows of weeks, stacked, so each square can be bigger:
<ContributionGrid data={days} bands={2} />
In a slim column, run the weeks down instead, with the month names on the left:
Or show fewer weeks with startDate, here the last three months, in weeks that start on Monday:
Examples
A Year
Without Month Names
Example Widget
GitHub's API gives a year as weeks of days, so flatten them into one list:
import { ContributionGrid } from "~lib/charts/contribution-grid";
const Contributions = ({ calendar }) => (
<ContributionGrid
data={calendar.weeks.flatMap((week) =>
week.contributionDays.map((day) => ({
date: day.date, // e.g. "2026-10-05"
value: day.contributionCount,
})),
)}
/>
);
See Also
- Heatmap - A grid of any rows and columns, shaded with patterns
- MonthlyCalendar - A month of events