HeatCell
React heat cell chart — one intensity cell for a table cell or matrix slot. Tiny accessible SVG microchart; RSC-safe static or /interactive.
HeatCell answers "how intense is this one value against a known scale?". It is the single-cell building block for grids you lay out yourself — a matrix of tenants × hours, a custom calendar, a density chip in a sentence. Color is quantized into discrete steps: continuous opacity would fake precision a 12-px cell can't deliver.
Install
import { HeatCell } from "@microcharts/react/heat-cell";<HeatCell value={42} domain={[0, 100]} title="Load" />Try it
When to use it
- Good for — table-cell matrices, custom grids, intensity chips beside labels.
- Avoid for — precise comparison (MiniBar, DotPlot) or time series (HeatStrip, ActivityGrid).
The shared-domain rule
A lone cell has no data to auto-scale from, so domain defaults to [0, 1] — pass your grid's real scale. Every cell
in one grid must share one domain: per-cell auto-scaling would make the brightest hour of a quiet tenant look like the
brightest hour of a loud one.
// one domain, computed once, shared by every cell
const domain: [number, number] = [0, Math.max(...allValues)];
rows.map((r) => r.hours.map((v) => <HeatCell value={v} domain={domain} />));Sizing
Variants
Edge cases
Four homes
Why this default
Five steps is the most a reader reliably distinguishes at cell size — the same ramp ActivityGrid uses, so intensity means one thing across the library. Values outside the domain clamp to the end steps (documented, never silently rescaled), and a zero-width domain renders the single mid step with a dev warning.
Accessibility
The accessible name carries the value and its calibration — the shape cells above read "70 — level 4 of 5." — so the color scale is never the only channel. Non-finite input renders a designed empty track and says "No data." The interactive entry reveals the same reading on hover/focus, with ActivityGrid announcement parity.
This chart is a single unit, so there is nothing to rove between: a click, tap, Enter or Space selects it
and fires onSelect, and no selection stays pinned. That is the scalar half of the shared
interaction contract.
Props
| Prop | Type | Notes |
|---|---|---|
| value* | number | The value to calibrate. |
| domain | [number, number] | Calibration scale — defaults to [0, 1]; every cell in a grid must share one. |
| steps | number | Discrete perceptual steps (default 5, shared with ActivityGrid). |
| shape | "square" | "round" | "dot" | Shared cell vocabulary. |
| label | "value" | "none" | Centered number when the cell doubles as a chip. |
| 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.
Related charts
StatusDot
React status dot chart — discrete state double-encoded by color and shape. Tiny accessible SVG microchart; RSC-safe static or /interactive.
Progress
React progress chart — elapsed fraction with a percent label, step segments, and honest >100% handling. Tiny accessible SVG microchart; RSC-safe static or /interactive.