HeatCell
React heat cell chart — one intensity cell for a table cell or matrix slot. Tiny accessible SVG microchart; RSC-safe static or /interactive.
- encodes
- discrete color step
- precision
- low — use MiniBar/DotPlot for precise comparison
- nodes
- ≤ 2 (cell + optional value label)
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.
Hover or focus also reveals the reading itself in a floating chip, for the sizes and label modes where the mark
does not print it; readout={false} drops the chip and keeps everything else.
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.