Skip to main content

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​

NameTypeRequiredDefaultDescription
data{ date: Date | string | number; value: number }[]YesN/AThe count for each day. Values given for the same day add up
startDateDate | string | numberNoFirst day givenThe first day to show
endDateDate | string | numberNoLast day givenThe last day to show
bandsnumberNo1Cut 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
monthsbooleanNotrueName each month over the week it starts in, where there is room
timeZonestringNoFrame time zoneTime zone a Date or timestamp falls on its day in, such as "Europe/London"
localestringNoFrame languageLanguage of the month names, such as "fr-FR"
widthnumber | stringNo"100%"Width, in pixels or any CSS length
heightnumber | stringNo"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 in timeZone

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} />
Open Two Bands in Storybook
Open Three Bands in Storybook

In a slim column, run the weeks down instead, with the month names on the left:

Open Column in Storybook

Or show fewer weeks with startDate, here the last three months, in weeks that start on Monday:

Open Last Three Months in Storybook

Examples​

A Year​

Open Year in Storybook

Without Month Names​

Open No Month Names in Storybook

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​