# HeatStrip (/docs/charts/heat-strip)

HeatStrip answers "how did intensity evolve, glanceably?". It is the 1×N sibling of ActivityGrid: the same discrete step
scale, the same cell vocabulary, laid on a single timeline. Empty is not zero — a slot with no record renders a hairline
outline, visibly different from a low value.

```tsx
<HeatStrip
  data={[12, 25, 38, 52, 66, 79, 88, 90, 84, 71, 55, 40, 28, 45, 62, 78, 85, 74, 58, 35]}
  domain={[0, 100]}
  title="Load per hour"
  width={240}
  height={20}
/>
```

## Install

```tsx
import { HeatStrip } from "@microcharts/react/heat-strip";

<HeatStrip data={hourlyLoad} domain={[0, 100]} title="Load per hour" />
```

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** — per-tenant load rows, intensity ribbons in dense tables.
- **Avoid for** — exact shape (Sparkline) or weekday rhythm (ActivityGrid).


## Variants

```tsx
const load = [12, 38, 66, 88, 84, 55, 28, 62, 85, 58];

<HeatStrip data={load} domain={[0, 100]} shape="round" />
<HeatStrip data={load} domain={[0, 100]} shape="dot" />
```

## Edge cases

```tsx
<HeatStrip data={[3, null, 8, null, 5]} />
```


## Why this default

Square cells with a density-adaptive gap keep boundaries legible where round shapes blur at 10 px. Every real value
renders at a visible opacity (0.25–1); the faint track look is reserved for truly-empty slots. Three ways a heat strip
lies — continuous ramps, per-row autoscale, mean-based downsampling — are all closed: discrete steps, shared `domain`,
max-per-bucket only.

## Accessibility

The summary reuses `describeSeries` verbatim — for the load strip above that's **"Trending up 383%. Range 12 to 88. Last
value 58."** — so a color ramp is never the only channel. The interactive entry roves cells with ActivityGrid-parity
announcements (**"Point 8 of 20: 90."**, empty slots as "no data").

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 \| null)[]` | Time-ordered values; null = no record (≠ zero). |
| `steps` | `number` | Shared step-scale granularity (default 5). |
| `shape` | `"square" \| "round" \| "dot"` | Shared cell vocabulary. |
| `domain` | `[number, number]` | Cross-row calibration — share one domain per table. |
| `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).
