# heat-graph URL: /docs/utilities/heat-graph Headless, composable activity heatmap components for React. import { Callout } from "fumadocs-ui/components/callout"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; import { HeatGraphDemo } from "@/app/heat-graph/heat-graph-demo"; `heat-graph` provides headless, Radix-style primitives for building GitHub-style activity heatmap graphs. * **Composable** — Radix-style compound components you fully control * **Headless** — Zero styling opinions, bring your own CSS/Tailwind * **Tooltip built-in** — Powered by Radix Popper for positioning * **Customizable bucketing** — Plug in your own classification function Installation \[#installation] ```sh npx shadcn@latest add https://r.assistant-ui.com/heat-graph ``` This installs a pre-styled `HeatGraph` component to `components/assistant-ui/heat-graph.tsx` along with the `heat-graph` package. ```sh npm install heat-graph ``` ```sh pnpm add heat-graph ``` ```sh yarn add heat-graph ``` Quick Start \[#quick-start] ```tsx title="components/activity-graph.tsx" "use client"; import * as HeatGraph from "heat-graph"; const COLORS = ["#ebedf0", "#c6d7f9", "#8fb0f3", "#5888e8", "#2563eb"]; export function ActivityGraph({ data }: { data: HeatGraph.DataPoint[] }) { return ( {({ cells }) => cells.map((cell) => ( )) } {({ cell }) => (
{cell.count} contributions on {cell.date.toLocaleDateString()}
)}
); } ``` Components using Heat Graph must be Client Components (`"use client"`), since they rely on React Context and interactivity. Anatomy \[#anatomy] ```tsx import * as HeatGraph from "heat-graph"; {/* Month labels */} {({ labels, totalWeeks }) => labels.map((l) => ( {HeatGraph.MONTH_SHORT[l.month]} ))} {/* Day-of-week labels */} {({ labels }) => labels.map((l) => ( {HeatGraph.DAY_SHORT[l.dayOfWeek]} ))} {/* Grid + Cells */} {({ cells }) => cells.map((cell) => ( ))} {/* Legend */} {({ items }) => items.map((item) => ( ))} {/* Tooltip */} {({ cell }) =>
{cell.count} on {cell.date.toLocaleDateString()}
}
``` API Reference \[#api-reference] Root \[#root] The top-level provider. Renders a `
` that computes the grid layout and provides state to all children. Accepts all standard div props. | Prop | Type | Default | Description | | ------------ | ---------------------- | ------------------- | -------------------------------------------------- | | `data` | `DataPoint[]` | required | Array of `{ date: string \| Date, count: number }` | | `start` | `string \| Date` | 1 year before `end` | Start of the date range | | `end` | `string \| Date` | today | End of the date range | | `weekStart` | `"sunday" \| "monday"` | `"sunday"` | First day of the week | | `classify` | `ClassifyFn` | `autoLevels(5)` | Bucketing function mapping counts to levels | | `colorScale` | `string[]` | — | Array of colors, one per level (index 0 = lowest) | Grid \[#grid] A `
` with CSS Grid layout. Renders `gridTemplateColumns` and `gridTemplateRows` based on the computed data. Accepts all standard div props. Provides a `CellCollection` via render prop. The `.map()` callback receives a `CellData` object and automatically wraps each element in the context needed by `Cell`. ```ts type CellData = { date: Date; count: number; level: number; column: number; row: number; }; ``` Cell \[#cell] A `
` that reads from cell context. Automatically applies: * Grid positioning (`gridColumn`, `gridRow`) * Background color from `colorScale` * Tooltip hover handlers Accepts all standard div props. Pass `colorScale` to override the Root-level color scale. MonthLabels \[#monthlabels] Render prop component providing month label data. ```tsx {({ labels, totalWeeks }) => labels.map((label) => ( {HeatGraph.MONTH_SHORT[label.month]} )) } ``` Provides `{ labels, totalWeeks }`. Each label has `{ month: number, column: number }`. Use `totalWeeks` to compute label positions. Use `MONTH_SHORT[label.month]` for English labels, or format with `Intl.DateTimeFormat` for localization. DayLabels \[#daylabels] Render prop component providing day-of-week label data. ```tsx {({ labels }) => labels.map((label) => ( {HeatGraph.DAY_SHORT[label.dayOfWeek]} )) } ``` Each label has `{ dayOfWeek: number, row: number }` where `dayOfWeek` is 0=Sun..6=Sat. Use `DAY_SHORT[label.dayOfWeek]` for English labels, or format with `Intl.DateTimeFormat` for localization. Legend \[#legend] Render prop component providing legend items. Each item has `{ level: number, color: string | undefined }`. LegendLevel \[#legendlevel] A `
` that reads from legend item context. Automatically applies `backgroundColor` from the color scale. Use inside `Legend`'s `.map()`. Tooltip \[#tooltip] Renders only when a cell is hovered. Positioned by Radix Popper relative to the hovered cell. Accepts Radix Popper `Content` props (`side`, `sideOffset`, `align`, etc.). ```tsx {({ cell }) =>
{cell.count} contributions
}
``` autoLevels(n) \[#autolevelsn] Default classification function. Maps counts into `n` evenly-distributed levels (0 to n-1). Level 0 is always count 0. ```ts type ClassifyFn = (counts: number[]) => (count: number) => number; ``` To provide a custom classifier: ```tsx const myClassify: HeatGraph.ClassifyFn = (counts) => { const p75 = percentile(counts, 75); return (count) => { if (count === 0) return 0; if (count < p75 * 0.25) return 1; if (count < p75 * 0.5) return 2; if (count < p75) return 3; return 4; }; }; ``` MONTH\_SHORT \[#month\_short] English month abbreviations array: `["Jan", "Feb", ..., "Dec"]`. Index by `MonthLabel.month`. DAY\_SHORT \[#day\_short] English day abbreviations array: `["Sun", "Mon", ..., "Sat"]`. Index by `DayLabel.dayOfWeek`.