Skip to content
microcharts
ReferenceCoreActivityGrid

ActivityGrid

React activity grid chart — contribution-graph intensity on a calendar or matrix. Tiny accessible SVG microchart; RSC-safe static or /interactive.

ActivityGrid maps ordered values onto a grid of cells, each shaded by intensity. It's the contribution-graph shape: cadence, streaks, and seasonality, readable at a glance.

ActivityGrid
interactive · 5.06 kB · static · 2.36 kB

Install

Import & usereact/activity-grid
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,];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — daily activity, streaks and cadence, seasonality at a glance.
  • Avoid for — exact values, or precise comparison between two individual cells. Color intensity is deliberately approximate; 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.

grid (default) vs strip

shape swaps the cell mark — same data, same levels, different voice: "round" for friendlier product surfaces, "dot" adds breathing room in dense strips.

round vs dot

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 — Monday first by default (weekStart={0} for Sunday).

calendar-aligned

Edge cases

empty data
all-zero (present, quiet)
single cell

Four homes

Why this default

Five levels (the empty track plus four intensity steps) matches the five steps HeatCell and HeatStrip default to, and the four intensity steps share their exact opacity ramp — one calibration means "how intense" reads the same across the library, and a reader never has to relearn a color scale per chart. Only level 0 differs: here it is a faint empty track, because an activity slot with no activity is genuinely empty, not a bottom-of-scale value. Levels are discrete, never a continuous gradient: a continuous ramp implies precision a handful of pixels can't actually deliver, and discrete bins are honest about that. Monday-first weeks (weekStart={1}) match the ISO calendar most teams already track cadence against; weekStart={0} switches to Sunday-first without touching the data. Column-major fill (each column is a week, top-to-bottom) is what makes the grid read as a calendar instead of an arbitrary sequence of cells.

Accessibility

Intensity is a color channel, so ActivityGrid always pairs it with a numeric summary of its total and peak — the information survives forced-colors and color-blind viewing. The interactive entry adds 2-D arrow-key navigation, announcing each cell's value as you move.

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

PropTypeNotes
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.
anchorstring | DateFirst slot's calendar day (UTC) — pads the first column so weekday rows align.
weekStart0 | 1Start of week for anchor alignment (0 Sunday, 1 Monday).
cellnumberCell edge length in viewBox units.
domain[number, number]Explicit range for level bucketing.
titlestringAccessible name; joins the auto summary.
summarystring | falseOverride or disable the auto summary.
animatebooleaninteractiveOpt-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.

Related charts