Yugen UI

Heatmap

Heatmap colors a row × column matrix by magnitude, for hour / day patterns, cohort comparisons or retention tables.

By default it uses a single-hue sequential scale (light = small, dark = large); diverging switches to two poles around midpoint, with neutral gray at the middle. Cells are 2px apart, and row / column labels are truncated to fit (the full text is in the tooltip and table). Empty cells get a neutral hatch pattern and are read as “No data”. The legend is a color gradient with min / max labels. Keyboard: Tab into the matrix, arrows move between cells, Home/End go to the start/end of the row.
Yugen Labs · experimentalThis component is outside SemVer: its API can change in a minor release, and What's new says so. Versioning policy
Visits by hour
Average of the last 4 weeks (thousands)
3110

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { Heatmap } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Year-over-year growth
-30%0%+30%

Diverging

Signed data (up / down): diverging + a symmetric domain so both poles are equally dark; 0 is gray.

Retention by signup cohort
0%100%
No data

Empty cells (cohort table)

null means “no data yet”. It is drawn with a neutral pattern, not the lightest color of the scale, which would read as “close to 0”.

Usage

Do
  • Use a sequential scale for unsigned magnitudes; use a diverging scale only when the midpoint means something (0, a target, an average).
  • Fix the domain when comparing several heatmaps, so the same color means the same value.
  • Order rows / columns naturally (days of the week, hours) or by value so patterns show up.
Don't
  • Don't use categorical colors for cells. A heatmap encodes magnitude, not identity.
  • Don't give empty cells the lightest color. Missing data isn't the same as a small value.
  • Don't cram number labels into small cells; the exact values are in the tooltip and table.

Props

Prop · TypeDefaultDescription
data / indexChartDatum[] / stringDefault: —Each item is a row; index is the row label field.
columns{ key: string; label: string }[]Default: —Columns; null/missing = empty cell.
domain[number, number]Default: from the dataColor domain; values outside it are clamped.
diverging / midpointboolean / numberDefault: false / 0Diverging scale around midpoint.
valueFormatChartNumberFormatDefault: —Value format (legend, tooltip, table).
rowHeightnumberDefault: 32Height of each row (px); the total height is computed.
legendbooleanDefault: trueColor gradient with min / max labels (and the midpoint).
title, description, toolbar, locale, ariaLabel, indexLabel…ChartFramePropsDefault: —Same as BarChart: frame, “Data table” button, texture, animate (off under reduced motion).

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.chart

Key · TypeDefault (English)messagesVi
roleDescriptionstring

aria-roledescription của vùng vẽ.

Default (English)"chart"messagesVi"biểu đồ"
heatmapRoleDescriptionstringDefault (English)"heat map"messagesVi"bản đồ nhiệt"
dataTablestring

Nút bật chế độ bảng của ChartContainer.

Default (English)"Data table"messagesVi"Bảng dữ liệu"
totalstring

Dòng tổng (tooltip, bảng) và nhãn giữa vòng DonutChart.

Default (English)"Total"messagesVi"Tổng"
valuestringDefault (English)"Value"messagesVi"Giá trị"
sharestringDefault (English)"Share"messagesVi"Tỉ lệ"
noDatastringDefault (English)"No data"messagesVi"Không có dữ liệu"
timestring

Tiêu đề cột đầu của bảng (khi không truyền indexLabel).

Default (English)"Time"messagesVi"Thời gian"
categorystringDefault (English)"Category"messagesVi"Danh mục"
groupstringDefault (English)"Group"messagesVi"Nhóm"
namestringDefault (English)"Name"messagesVi"Tên"
otherstring

Nhóm gộp (DonutChart vượt maxSlices, ScatterChart nhóm thứ 9+).

Default (English)"Other"messagesVi"Khác"
trendstring

Nút bật đường xu hướng của ScatterChart.

Default (English)"Trend"messagesVi"Xu hướng"
increasestringDefault (English)"Increase"messagesVi"Tăng"
decreasestringDefault (English)"Decrease"messagesVi"Giảm"
noChangestringDefault (English)"No change"messagesVi"Không đổi"
brushstring

ChartBrush: tên cửa sổ thu phóng, dòng "Đang xem … · n/N mốc", nút đặt lại.

Default (English)"Visible range"messagesVi"Vùng xem"
brushRoleDescriptionstringDefault (English)"zoom window"messagesVi"cửa sổ thu phóng"
brushViewingstringDefault (English)"Showing"messagesVi"Đang xem"
brushPoints(shown: number, total: number) => stringDefault (English)(shown, total) => `${shown}/${total} ${total === 1 ? "point" : "points"}`messagesVi(shown, total) => `${shown}/${total} mốc`
brushResetstringDefault (English)"Reset"messagesVi"Đặt lại"
lineSummary(info: { kind: "line" | "area" | "stacked" | "expand"; points: number; /** Mốc đầu / cuối (chỉ có khi points > 0). */ from?: string; to?: string; series: string[]; }) => string

Mô tả truy cập tự sinh (khi không truyền ariaLabel).

Default (English)Function, see messages.tsmessagesViFunction, see messages.ts
barSummary(info: { horizontal: boolean; stacked: boolean; categories: number; series: string[] }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
donutSummary(info: { groups: number; total: string; largest?: { label: string; share: string } }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
scatterSummary(info: { points: number; x: string; y: string; /** Tên đại lượng kích thước (biểu đồ bong bóng). */ size?: string; /** Tên các nhóm (khi có nhiều nhóm). */ groups?: string[]; trends: { group?: string; slope: string; r2: string }[]; }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
heatmapSummary(info: { rows: number; columns: number; min?: string; max?: string; hasEmpty: boolean }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
sparklineSummary(info: { points: number; first: string; last: string; min: string; max: string }) => stringDefault (English)Function, see messages.tsmessagesVi({ points, first, last, min, max }) => `Xu hướng ${points} điểm: từ ${first} đến ${last}, thấp nhất ${min}, cao nhất ${max}`