Heatmap
heatmapMaps matrix values to color intensity with labels, legends, empty states, and drill-down.
Usage
Basic usage
Pass the sparse point set data + row and column labels, and automatically map to the main color transparency file by value.
<Heatmap data={data} xLabels={WEEKDAYS} yLabels={MODULES} cellSize={18} />Contribution Activity Diagram
GitHub-style 12-week active heat with the grid turned down for a more compact fit.
<Heatmap
data={contribData}
xLabels={weeks}
yLabels={["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]}
cellSize={14}
/>Number of color levels
colorScale controls the color level binning. The more bales there are, the more delicate the transition will be.
<Heatmap data={data} xLabels={WEEKDAYS} yLabels={MODULES} colorScale={9} />Label-less compact
showLabels={false} hides row and column labels, suitable for putting into cards as thumbnails.
<Heatmap data={data} xLabels={WEEKDAYS} yLabels={MODULES} showLabels={false} cellSize={12} />Decimal Value Field / Percent + Legend
The ratio data (0–1) passed to domain tightens the value range and fills the color scale; valueFormat makes tooltip and the legend automatically add %; showLegend displays the color scale legend.
<Heatmap
data={masteryData} // value is a mastery rate of 0.5~0.85
xLabels={TOPICS}
yLabels={CLASSES}
domain={[0.5, 0.9]} // Binning according to the proportion of the value range, the low range can also be filled with color levels
valueFormat={(v) => `${Math.round(v * 100)}%`}
showLegend
cellSize={18}
/>No data vs value is 0
The absent cell (there is no such point in data) defaults to the same color as the 0 level; pass emptyCellTone and paint it in an independent style to separate it from the "real 0". The legend will automatically fill in a "no data" sample.
<Heatmap
data={masterySparse} // The function/geometric grid of class 3 is absent, the equation of class 4 is real 0
xLabels={TOPICS}
yLabels={CLASSES}
domain={[0, 1]}
valueFormat={(v) => `${Math.round(v * 100)}%`}
emptyCellTone="repeating-linear-gradient(45deg, var(--color-border) 0 2px, transparent 2px 4px)"
showLegend
formatTooltip={(c) => (c.empty ? `${c.y} · ${c.x}: Not answered` : `${c.y} · ${c.x}: ${Math.round(c.value * 100)}%`)}
/>Custom prompt + drill down
formatTooltip Customize the hover copy; after passing onCellClick, the grid becomes a clickable button.
<Heatmap
data={data}
xLabels={WEEKDAYS}
yLabels={MODULES}
formatTooltip={(c) => `${c.y} in ${c.x}: ${c.value} questions`}
onCellClick={(c) => alert(`${c.y} · ${c.x}`)}
/>When to use
Use Heatmap to expand sparse {x, y, value} points into a two-dimensional intensity grid, such as contribution activity, module-by-time hotspots, coverage, or mastery matrices. Use Table or ProTable when cells need rich content, sorting, or pagination.
Import
import { Heatmap, buildMatrix, bucketize } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| data* | HeatCell[] | — | Sparse {x, y, value} points. |
| xLabels | (string|number)[] | Derived from data | Explicit column labels. |
| yLabels | (string|number)[] | Derived from data | Explicit row labels. |
| colorScale | number | 5 | Number of color levels. |
| max | number | Data maximum | Full-scale value; domain takes precedence when supplied. |
| domain | [number, number] | [0, max] | Explicit value range used to bucket (value-min)/(max-min); values at or below min use level zero. |
| valueFormat | (value: number) => string | String | Formats tooltip and legend values and takes precedence over unit. |
| unit | string | — | Suffix appended to raw values; use valueFormat for numeric conversion. |
| emptyCellTone | string | — | CSS background for absent points. Without it, absent cells share the zero-level color. |
| showLegend | boolean | false | Shows range labels, color blocks, and an absent-data sample when emptyCellTone is set. |
| cellSize | number | 14 | Cell side length in pixels. |
| gap | number | 3 | Gap between cells in pixels. |
| showLabels | boolean | true | Shows row and column labels. |
| formatTooltip | (cell: HeatmapCellInfo) => string | — | Formats the native hover title. Check cell.empty before using its zero fallback value. |
| className | string | — | Custom class name. |
HeatmapCellInfo, passed to formatTooltip and onCellClick:
| Field | Type | Description |
|---|---|---|
| x / y | string|number | Column and row labels. |
| value | number | Cell value; absent cells use 0, so this does not indicate presence. |
| empty | boolean | Whether the point is absent from data; the optional typing preserves compatibility. |
Events
| Event | Type | Description |
|---|---|---|
| onCellClick | (cell: HeatmapCellInfo) => void | Fires when a cell is selected for drill-down. |
Pitfalls
Use deterministic data; generating showcase values with Math.random() can make SSR and CSR color levels disagree. Set the same max or domain when comparing multiple heatmaps.
unitonly appends text. For a 0-1 ratio,unit="%"produces0.55%; usevalueFormatto convert it to a percentage.- Decimal data now defaults to its actual maximum. Pass
max={1}if you require the earlier fixed-one behavior. - Values at or below the domain minimum use the lightest level, so place min below the lowest meaningful data point.
- Without
emptyCellTone, absent data and zero share a color. Set it when those states have different meanings. - Test
cell.empty, notcell.value === 0, because absent cells use zero as a compatibility fallback. Custom tooltip logic must make the same distinction. The built-in absent label is the runtime string"\u65e0\u6570\u636e"("No data"). - The legend accessibility label follows the runtime template `
\u8272\u9636\uff1a${formatValue(domainMin)} \u81f3 ${formatValue(domainMax)}` ("Color scale: minimum to maximum"). buildMatrix(...).get(y, x)returnsundefinedfor an absent point; direct consumers can useget(y, x) ?? 0when a numeric fallback is required.
Related
Table · Book3D · ProTable · PricingTable · JsonViewer · EditableTable
Playground
<Heatmap data={data} colorScale={5} cellSize={16} />