Skip to content
microcharts
ReferenceCoreHeatCell

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.

HeatCell
interactive · 3.26 kB · static · 2.02 kB

Install

Import & usereact/heat-cell
import { HeatCell } from "@microcharts/react/heat-cell";<HeatCell value={42} domain={[0, 100]} title="Load" />
Needs package + stylesheetSet up with AI

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

shapes
value chip

Edge cases

non-finite value — a designed empty track
value at the domain floor and ceiling — clamped, not rescaled

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

PropTypeNotes
value*numberThe value to calibrate.
domain[number, number]Calibration scale — defaults to [0, 1]; every cell in a grid must share one.
stepsnumberDiscrete 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.
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