Heat Calendar
Shows daily activity on a calendar.
Installation
pnpm dlx shadcn@latest add @paneui/heat-calendarUsage
Composition
Examples
Selecting ranges
Drag across days with the pointer. With the keyboard, the arrow keys move between days, Enter or Space starts and then ends a range, Shift + arrows extend it and Esc clears.
Dates
All dates are UTC YYYY-MM-DD strings. Days after endDate render as empty placeholders, and the grid starts scrolled to the latest week.
HeatCalendar
Root and context. Without children it renders the grid with tooltip, then summary and legend. Also accepts every prop of div.
- data*
- { date: string; count: number }[]
- Daily counts; duplicates are summed.
- endDate= latest date in data
- string
- Last UTC day shown.
- weeks= 26
- number
- Number of week columns.
- weekStartsOn= 0
- 0 | 1
- 0 = Sunday, 1 = Monday.
- unit= the locale's
- string
- Noun after every count.
- color= "var(--chart-4, var(--success))"
- string
- The single hue; strength maps to count.
- maxCount= visible maximum
- number
- Count that maps to the strongest level.
- cellSize= 12
- number
- Cell size in px.
- gap= 3
- number
- Gap between cells in px.
- label= the locale's
- string
- Accessible name.
- selection
- { start: string; end?: string } | null
- Controlled selected range.
- defaultSelection= null
- { start: string; end?: string } | null
- Initially selected range.
- onSelectionChange
- (selection) => void
- Called when a range is started, finished or cleared.
- children
- ReactNode
- Custom composition of parts.
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | { date: string; count: number }[] | — | Daily counts; duplicates are summed. |
| endDate | string | latest date in data | Last UTC day shown. |
| weeks | number | 26 | Number of week columns. |
| weekStartsOn | 0 | 1 | 0 | 0 = Sunday, 1 = Monday. |
| unit | string | the locale's | Noun after every count. |
| color | string | "var(--chart-4, var(--success))" | The single hue; strength maps to count. |
| maxCount | number | visible maximum | Count that maps to the strongest level. |
| cellSize | number | 12 | Cell size in px. |
| gap | number | 3 | Gap between cells in px. |
| label | string | the locale's | Accessible name. |
| selection | { start: string; end?: string } | null | — | Controlled selected range. |
| defaultSelection | { start: string; end?: string } | null | null | Initially selected range. |
| onSelectionChange | (selection) => void | — | Called when a range is started, finished or cleared. |
| children | ReactNode | — | Custom composition of parts. |
HeatCalendarGrid
The scrollable day grid with month and weekday labels.
- children= <HeatCalendarTooltip />
- ReactNode
- Overlay rendered over the grid.
- className
- string
- Classes for the outer element.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | <HeatCalendarTooltip /> | Overlay rendered over the grid. |
| className | string | — | Classes for the outer element. |
- data-level
- On each cell: 0 (empty) to 4 (strongest).
- data-selected
- On cells inside the selected range.
| Data attribute | Description |
|---|---|
| data-level | On each cell: 0 (empty) to 4 (strongest). |
| data-selected | On cells inside the selected range. |
HeatCalendarTooltip
- children
- (day: { date: string; time: number; count: number; level: number }) => ReactNode
- Custom body for the hovered or focused day.
- className
- string
- Classes for the tooltip.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | (day: { date: string; time: number; count: number; level: number }) => ReactNode | — | Custom body for the hovered or focused day. |
| className | string | — | Classes for the tooltip. |
HeatCalendarSummary
Total for the period, or for the selected range with active days and Clear. Also accepts every prop of div.
generateHeatCalendarData
Deterministic demo data with quieter weekends, called as generateHeatCalendarData(rand, options).
- rand*
- () => number
- Random source (first argument).
- endDate= "2026-10-13"
- string
- Last day generated.
- days= 371
- number
- Number of days.
- intensity= 9
- number
- Rough maximum daily count.
| Prop | Type | Default | Description |
|---|---|---|---|
| rand* | () => number | — | Random source (first argument). |
| endDate | string | "2026-10-13" | Last day generated. |
| days | number | 371 | Number of days. |
| intensity | number | 9 | Rough maximum daily count. |