# ActivityGrid (/docs/charts/activity-grid)

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.

```tsx
import { ActivityGrid } from "@microcharts/react/activity-grid";

const commitCounts = [ 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, ];

<ActivityGrid data={commitCounts} title="Commit activity" />
```

## Install

```tsx
import { ActivityGrid } from "@microcharts/react/activity-grid";

<ActivityGrid data={commits} title="Commits" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## 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.

```tsx
const commits = [0, 1, 2, 1, 3, 4, 2, 0, 1, 3, 2, 4, 3, 1, 0, 2, 4, 3, 2, 1];

<ActivityGrid data={commits} />
<ActivityGrid data={commits.slice(0, 12)} layout="strip" />
```

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

```tsx
const commits = [0, 1, 2, 1, 3, 4, 2, 0, 1, 3, 2, 4, 3, 1, 0, 2, 4, 3, 2, 1];

<ActivityGrid data={commits} shape="round" />
<ActivityGrid data={commits.slice(0, 12)} layout="strip" shape="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).

```tsx
// data[0] is Thursday 1970-01-01 → three leading empty slots
<ActivityGrid
  data={[2, 3, 1, 4, 2, 0, 1, 3, 2, 4, 3, 1, 0, 2, 4, 3, 2, 1]}
  anchor="1970-01-01"
/>
```

## Edge cases

```tsx
<ActivityGrid data={[]} title="No history" />
```

```tsx
<ActivityGrid data={[0, 0, 0, 0, 0, 0, 0]} title="Quiet week" />
```

```tsx
<ActivityGrid data={[3]} title="One day" />
```


## 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](/docs/accessibility#one-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 | Description |
| --- | --- | --- |
| `data` (required) | `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. |
| `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. |
| `animate` | `boolean` | (interactive) Opt-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](/docs/quickstart#the-shared-grammar).
