ActivityGrid
"Contribution-graph intensity: ordered values on a grid of cells, shaded in four discrete steps over an empty track."
- encodes
- color intensity (discrete levels) over a grid
- precision
- low — steer to SparkBar when exact comparison matters
- nodes
- 1 per cell
Each cell is one slot in the series, shaded by intensity: the contribution-graph shape, read for cadence, streaks, and seasonality. There are five levels — a faint empty track plus four intensity steps — and the four steps share the exact opacity ramp HeatCell and HeatStrip use, so "how intense" means the same thing across the library. Level 0 is the empty track, because a slot with no activity is empty rather than a bottom-of-scale value. The steps are discrete bins, never a continuous gradient: a continuous ramp implies precision a handful of pixels can't deliver.
Install
import { ActivityGrid } from "@microcharts/react/activity-grid";// commits — real values under “Sample data” below<ActivityGrid data={commits} title="Commits" />Sample data
const commits = [ 0, 1, 2, 1, 3, 4, 2, 0, 1, 3, 2, 4, 3, 1, 0, 2, 4, 3, 2, 1, 3, 0, 2, 3, 4, 1, 2, 0, 1, 2, 3, 4, 2, 1, 0,];Try it
When to use it
Use it for daily activity, streaks and cadence, and seasonality. Avoid it for exact values or for a precise comparison between two individual cells: color intensity is deliberately approximate, so pair it with a number when precision matters.
Sizing
ActivityGrid sizes from cell — the edge length of one square in viewBox units. Bump it to scale the whole grid, or
drive the width from CSS to fill a container; the viewBox keeps the grid's aspect ratio.
Variants
layout="strip" collapses to a single row for inline use.
shape swaps the cell mark without changing the data or the levels. "round" softens the grid for product surfaces;
"dot" adds space between cells in dense strips.
anchor aligns the grid to the real calendar: the first column pads down to the weekday of the given day (UTC), so rows
read as weekdays. Weeks start on Monday by default (weekStart={1}, matching the ISO calendar); weekStart={0}
switches to Sunday without touching the data. Cells fill column-major — each column is a week, top to bottom — which is
what makes the grid read as a calendar rather than an arbitrary sequence.
Edge cases
Four homes
Accessibility
Intensity is a color channel, so ActivityGrid always pairs it with a numeric summary of its total and peak. That summary
survives forced-colors and color-blind viewing. The interactive entry adds 2-D arrow-key navigation, announcing each
cell's value as you move. Give it an anchor and every cell is a dated day, so the readout names the date rather than a
position ("Mar 2: 12").
The interactive entry follows the shared interaction contract:
arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or
Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape.
On touch, a tap pins and a drag scrubs.
Props
| Prop | Type | Notes |
|---|---|---|
| data* | number[] | Ordered values, one per cell. |
| layout | "grid" | "strip" | 7-row calendar or single strip. |
| shape | "square" | "round" | "dot" | Cell mark: crisp square, soft corners, or padded dot. |
| anchor | string | Date | First slot's calendar day (UTC) — pads the first column so weekday rows align. |
| weekStart | 0 | 1 | Start of week for anchor alignment (0 Sunday, 1 Monday). |
| cell | number | Cell edge length in viewBox units. |
| steps | number | Intensity steps including the zero track (default 5, GitHub-like). Same knob, same name, as CalendarStrip, CoverageStrip, GardenGrid, HeatCell, HeatStrip and SpiralYear. |
| domain | [number, number] | Explicit range for level bucketing. |
| title | string | Accessible name; joins the auto summary. |
| summary | string | false | Override or disable the auto summary. |
| gap | number | Gap between cells in viewBox units (default 2). |
| animate | boolean | interactiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion. |
Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.