Heat graph
An activity heat map with month labels, weekday labels, legend, and tooltip.
Installation
Install manually
npx shadcn@latest add "@assistant-ui/heat-graph"First time? Set up a runtime
Runtime components read their state from an assistant-ui runtime. Add one to an existing project:
npx assistant-ui@latest initThen wrap your app in a runtime provider:
import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";
export default function App() {
const runtime = useChatRuntime({
transport: new AssistantChatTransport({ api: "/api/chat" }),
});
return (
<AssistantRuntimeProvider runtime={runtime}>
{/* your components */}
</AssistantRuntimeProvider>
);
}The installation guide covers new projects, templates, and API routes.
npx shadcn@latest add "@assistant-ui/heat-graph"Props-driven: no runtime or provider required.
HeatGraph draws a GitHub-style activity calendar: a cell per day, colored by count, with month and weekday labels, a legend, and a hover tooltip. The assistant-ui runtime does not track daily activity counts, so this element has only a standalone form: you pass the counted days in.
Getting started
Pass counted days in
import { HeatGraph } from "@/components/assistant-ui/elements/heat-graph";
const data = [
{ date: "2026-01-01", count: 3 },
{ date: "2026-01-02", count: 0 },
{ date: new Date(2026, 0, 3), count: 7 },
];
export function Activity() {
return <HeatGraph data={data} />;
}date accepts either an ISO string or a Date; count is whatever unit you're measuring. The component sorts counts into one of five color levels for you.
The visible window is always the trailing year
HeatGraph never exposes start or end, the underlying primitive's own knobs for the date range, so the grid always covers the 365 days ending today, computed fresh at render time, aligned back to the start of its week. A data point outside that window, too old or dated in the future, is silently left off the grid rather than shown or reported as an error. If you need a fixed or a different window, compose the primitives yourself; see Editing the composition directly below.
Anatomy
<div>
<div>{/* month abbreviations, positioned over the grid's columns */}</div>
<div>
<div>{/* weekday abbreviations, every other row */}</div>
<div>{/* the cell grid, one column per week */}</div>
</div>
<div>{/* "Less" ... five legend swatches ... "More" */}</div>
<div>{/* hover tooltip: count and date */}</div>
</div>HeatGraph takes only data. There is no className prop and no data-slot marker on the root, both unlike the rest of the catalog, so a wrapping <div> is the only restyle hook you have from outside. Weeks start on Monday and the five-step scale is fixed by this file, not configurable through a prop: empty days take a faint tint of the foreground color edged with the border token, and busier days step up through blue, with a lighter blue under the dark variant, so the grid follows the page's theme. The calendar keeps a minimum cell size and scrolls sideways inside its own box when the container is too narrow for a full year. Weekday labels show on alternating rows rather than every row, and each month label sits over the first week that starts in that month, so a month whose first week falls before the window and a month that begins in the current week go unlabelled. The legend shows five swatches, one per color level, bracketed by "Less" and "More"; when no day in the window has a count above zero, it shows one. Hovering a cell shows a tooltip reading "{count} contributions on {date}", with the date spelled out as month, day, and year.
Examples
Editing the composition directly
Since there's no prop for it, changing the color scale, the week start, or the label and tooltip classes means editing heat-graph.tsx itself rather than passing a class name. The file is a thin composition over the heat-graph package's own primitives: Root, MonthLabels, DayLabels, Grid with Cell, Legend with LegendLevel, and Tooltip. Swap the LEVEL_TINT classes, pass colorScale or change weekStart on Root, or drop a sub-part (the legend, say) to change what renders.
<HeatGraphPrimitive.Root data={data} weekStart="sunday" classify={HeatGraphPrimitive.autoLevels(2)} colorScale={["#eee", "#0a5"]}>
{/* your own MonthLabels / DayLabels / Grid / Legend, or a subset of them */}
</HeatGraphPrimitive.Root>A second composition, elsewhere in the catalog
activity-graph builds its own calendar independently on the same heat-graph package primitives, with the shared paper and mono surface tokens and a className prop, rather than wrapping this file's HeatGraph. If you need a restylable calendar, start from Activity graph or the raw heat-graph primitives directly, rather than forking this fixed one.
API reference
HeatGraph
| Prop | Type | Default | Description |
|---|---|---|---|
data | DataPoint[] | required | One entry per counted day. Days missing from the array render as the lowest color level. |
DataPoint is { date: string | Date; count: number }, from the heat-graph package this element wraps.