# react-activity-calendar renders a GitHub style contribution heatmap from data you classify yourself

> react-activity-calendar is a React component that draws activity data as a calendar heatmap, with any number of activity levels including negative ones, colour themes, dark and light mode, tooltips, event handlers and localization. The component draws only what you give it, so the counting and the level classification stay in your code, and the documentation is explicit that Create React App is not supported.

**grubersjoe/react-activity-calendar** — React component for displaying activity data in a calendar (heatmap)

- Repository: https://github.com/grubersjoe/react-activity-calendar
- Website: https://grubersjoe.github.io/react-activity-calendar/
- Stars: 599 · Forks: 43
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/grubersjoe-react-activity-calendar

## The component draws squares, your code decides what a square means

react-activity-calendar is a React component to display activity data in a calendar, in the heatmap style made familiar by contribution graphs. The README is unusually clear about the division of labour. The component expects activity data in a specific shape, where each activity level must be in the bounds controlled by the minLevel and maxLevel props, and then states plainly: it is up to you how to generate and classify your data.

That is the whole design. There is no counting, no bucketing algorithm and no fetching. You pass an array of entries, each with a date, a count and a level, and the component lays them out on a calendar grid and colours each cell according to its level.

The data shape is simple:

```ts
import { ActivityCalendar } from 'react-activity-calendar'

const data = [
  {
    date: '2024-06-23',
    count: 2,
    level: 1,
  },
  {
    date: '2024-08-02',
    count: 16,
    level: 4,
  },
```

And rendering it is a single component call, with the data passed as a prop.

That the count and the level are separate fields is the part that matters for real use. The count is what you might show in a tooltip, and the level is what drives the colour. A component that computed the level from the count would force a fixed bucketing scheme on you, and any scheme other than quantile or linear would be impossible. Passing the level separately lets you rank days however your domain requires.

## Any number of levels, including negative ones

The feature list opens with the item that separates this from a straight copy of the contribution graph idea: any number of activity levels, including negative ones. The v3.2 release in the repository listing is titled Support negative activity levels, so this is a recent addition rather than an original feature.

The bounds are yours to set. By default the level bounds are [0, 4], but the README states that any range is possible, and points to the activity levels story in the documentation for the details. The defaults of five levels, zero through four, are the familiar GitHub-style four shades plus an empty state.

Being able to go negative changes what the component is for. A component locked to zero and above can only show intensity. One that accepts negative levels can show direction: days where something went below a baseline, days with net negative contributions, days where a metric fell. The colour themes and the light and dark mode support are what make that usable, since a negative band has to be visually distinguishable from zero in both colour schemes.

The consequence for you is that level assignment is entirely a naming exercise on your side. Nothing in the component knows what level 2 means, and the documentation is explicit that classification is your job. If your data has days you want hidden, you control that by choosing whether to include them or what level to give them.

## Themes, tooltips and handlers are props, not forks

The rest of the feature list is the set of things you would otherwise have to build yourself around a heatmap: colour themes, dark and light mode, tooltips, event handlers and localization.

The examples directory shows how much of this is exercised. There are files for activity levels, customization, event handlers, labels and labels shape, an explicit themes example alongside a general themes example, tooltips and tooltips config, weekdays all, and a ref example. The separate labels and labels shape files suggest the weekday and month labelling is configurable rather than fixed, and weekdays all hints at an option to show every weekday row rather than the usual subset.

The tooltips deserve a specific note, because the package exports them separately. The exports map in package.json has two entries: the root pointing at ./build/index.js, and ./tooltips.css pointing at ./build/tooltips.css. So the tooltip styling is a stylesheet the consumer has to import, and a component that renders without it will look unstyled. That is a small thing to trip over and an easy fix, but it is the kind of detail that makes an integration look broken on first contact.

The related projects are the same author's ecosystem. react-github-calendar sits alongside it, along with github-contributions-api, which is the piece that fetches contribution data in the first place. The activity calendar is the rendering half of that pair.

## Storybook is the documentation, and the examples are the spec

The documentation for this component is a Storybook site, hosted at grubersjoe.github.io/react-activity-calendar, and the README links to it from the top as the documentation entry point. The repository layout backs that up: there is a .storybook/ directory at the root, and the docs/ directory is the built output of a storybook build.

The two development commands are short:

```bash
npm run dev
```

That starts the Storybook on port 9000, and the other command, npm run build:storybook, rebuilds the docs directory and touches docs/.nojekyll so the output is served correctly by GitHub Pages.

The build script itself is a rollup build, and the package is published from the build/ directory along with src, the README and the tsconfig. The types are generated rather than hand written: the postbuild script runs dts-bundle-generator over src/index.tsx to produce build/index.d.ts, with react, date-fns and @floating-ui/react marked as external imports, and it runs with --no-check and --no-banner.

The three external libraries in that list describe the dependency surface. react is the host framework, date-fns is the date handling, and @floating-ui/react is the positioning library that makes the tooltip follow the cursor and stay inside the viewport. None of them are bundled into the output, which is why the type generator has to mark them as external.

## Visual tests run in a container, unit tests run in Vitest

The test setup is the part of the repository that says most about how the project is run.

The test script runs the unit tests and then the visual tests, with the unit tests handled by vitest run and the visual tests by a docker compose invocation that builds the Playwright service, runs it, and pipes it to the Playwright test runner inside the container. There is a separate update script for regenerating the visual baselines, and the Playwright configuration lives in playwright.config.ts at the root, with vitest.config.ts next to it.

The compose file explains why a container is needed. The Playwright service builds from the mcr.microsoft.com/playwright image, pinned to a version, with corepack enabled and pnpm prepared inside the image, and it sets the platform to linux/arm64. The project source is mounted into the container and node_modules and the pnpm store are separate named volumes, so the browser binaries installed in the image are not shadowed by the host's node_modules.

Visual regression testing for a component whose entire output is coloured squares is close to the right call. A level to colour mapping bug produces a plausible looking calendar with wrong shades, and no assertion on props would catch it.

The rest of the quality tooling is a check script that installs with a frozen lockfile and ignores scripts, then runs prettier in check mode, the TypeScript compiler, eslint and the unit tests, and a prepublishOnly script that runs that same check before the build. Husky handles the git hooks, with a prepare script that installs it.

## CRA is out, server side rendering is in, and version 3 was a breaking change

The README's FAQ answers two questions that would otherwise cost you an afternoon.

The first is about the calendar not rendering in a particular React framework. The answer points to a separate repository with working examples for Astro, Next.js, Remix and Vite, and states that server side rendering is supported. So if the component fails to appear, the problem is in the framework setup, and there is a known good configuration to copy.

The second is about Create React App, and the answer is a refusal. CRA is described as abandoned, with a link to the upstream discussion, and the README says using this component inside CRA will lead to errors for reasons described in an issue, and that the repository is not for CRA support questions. The author goes further and recommends Vite instead. That is a defensible position, since CRA has been effectively frozen for years, but it does mean a legacy codebase on CRA is out of scope.

Version 3 is a breaking change, and the README points to an upgrade guide in the documentation. The repository listing shows v3.0 published on 2025-11-15, followed by v3.1 and v3.2 on the same day in April 2026, with the v3.1 release adding a className prop and v3.2 adding support for negative activity levels. The current package version is 3.2.2, so the patch line has moved on since those tags.

On maintenance, the last push was on 2026-10-21 and the repository is not archived. The licence is MIT, recorded in the package.json and with a LICENSE file at the root, so there is no copyleft obligation on your application, which is a licensing note rather than legal advice.

## Conclusion

Adopt react-activity-calendar if you want a contribution style heatmap in a React app and you already have per day activity counts, because the component takes counts and levels and leaves the classification logic to you. Do not adopt it inside a Create React App project, since the README states CRA is abandoned and that using the component there leads to errors. Verify first that your level bounds are consistent with the minLevel and maxLevel props, that every date you pass is inside the range the component renders, and that your build setup can import the tooltips stylesheet, since the package exposes it as a separate export.

## FAQ

### How do I install react-activity-calendar?

Run npm install react-activity-calendar. The package is an ESM module with a root export pointing at the built JavaScript, and a separate ./tooltips.css export for the tooltip styles, which you import in your own stylesheet.

### What data shape does react-activity-calendar expect?

An array of entries, each with a date, a count and a level. The level must fall within the bounds set by the minLevel and maxLevel props, which default to [0, 4]. The component does not compute levels for you.

### Can react-activity-calendar show negative activity levels?

Yes. The feature list states any number of activity levels, including negative ones, and the v3.2 release is titled Support negative activity levels. The default bounds are [0, 4] but any range is possible through the minLevel and maxLevel props.

### Does react-activity-calendar work with Create React App?

No. The README states that CRA is abandoned, that using the component inside CRA leads to errors, and that the repository is not for CRA support questions. The author recommends Vite, and separate working examples exist for Astro, Next.js, Remix and Vite.

### How is react-activity-calendar tested?

Unit tests run with vitest run, and visual tests run through Playwright inside a docker compose service built from the Playwright image. The check script runs a frozen install, prettier in check mode, the TypeScript compiler, eslint and the unit tests, and it also runs as prepublishOnly.

## Sources

- [grubersjoe/react-activity-calendar on GitHub](https://github.com/grubersjoe/react-activity-calendar)
- [License: MIT](https://github.com/grubersjoe/react-activity-calendar/blob/main/LICENSE)
- [Project website](https://grubersjoe.github.io/react-activity-calendar/)
- [README](https://github.com/grubersjoe/react-activity-calendar/blob/main/README.md)
- [Releases](https://github.com/grubersjoe/react-activity-calendar/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/grubersjoe-react-activity-calendar
