/

Calendar Chart

Visualize daily data over a year as a grid of colored cells. The classic contribution heatmap for activity tracking and time patterns.

JanFebMarAprMayJunJulAugSepOctNovDecMonWedFriSun

Quick Start

import { CalendarChart } from "@chartts/react"
 
const data = [
  { date: "2025-01-01", value: 3 },
  { date: "2025-01-02", value: 7 },
  { date: "2025-01-03", value: 0 },
  { date: "2025-01-04", value: 12 },
  // ... daily entries for the year
]
 
export function ContributionGrid() {
  return (
    <CalendarChart
      data={data}
      date="date"
      value="value"
      year={2025}
      showMonthLabels
      showDayLabels
      className="w-full"
    />
  )
}

When to Use Calendar Charts

Calendar charts map data onto the familiar grid of weeks and months, making seasonal patterns and daily habits visible at a glance.

Use a calendar chart when:

  • Showing daily activity over a year (commits, workouts, sales)
  • Identifying patterns by day of week or time of year
  • Tracking streaks and consistency
  • The audience is familiar with GitHub-style contribution grids

Don't use a calendar chart when:

  • Data is not daily (use a line chart for hourly, or a bar chart for monthly)
  • You need to compare exact values precisely (cells are small)
  • Your data spans less than a few months (the grid looks sparse)

Props Reference

PropTypeDefaultDescription
dataT[]requiredArray of data objects with dates
datekeyof TrequiredKey for the date string (ISO format)
valuekeyof TrequiredKey for the numeric value
yearnumbercurrent yearWhich year to display
colorScalestring[]green scaleArray of colors from low to high
cellSizenumber12Size of each day cell in pixels
cellGapnumber2Gap between cells in pixels
showMonthLabelsbooleantrueDisplay month names along the top
showDayLabelsbooleanfalseDisplay day-of-week labels on the left
emptyColorstring"#ebedf0"Color for days with no data
animatebooleantrueAnimate cells on mount
classNamestring-Tailwind classes on root SVG

Color Scales

The color scale maps value intensity to color. Lower values get lighter colors, higher values get darker ones:

// Default green scale (GitHub-style)
<CalendarChart
  data={data}
  date="date"
  value="value"
  year={2025}
/>
 
// Blue scale
<CalendarChart
  data={data}
  date="date"
  value="value"
  colorScale={["#dbeafe", "#93c5fd", "#3b82f6", "#1d4ed8"]}
/>
 
// Purple scale
<CalendarChart
  data={data}
  date="date"
  value="value"
  colorScale={["#f3e8ff", "#c084fc", "#9333ea", "#581c87"]}
/>
 
// Red/heat scale
<CalendarChart
  data={data}
  date="date"
  value="value"
  colorScale={["#fee2e2", "#fca5a5", "#ef4444", "#991b1b"]}
/>

Values are automatically bucketed across the scale. Four colors means four intensity levels.


Year Navigation

Display a specific year by setting the year prop:

<CalendarChart
  data={data2024}
  date="date"
  value="value"
  year={2024}
  showMonthLabels
/>

To build a year picker, manage year in state and pass different data for each year:

const [year, setYear] = useState(2025)
 
<CalendarChart
  data={data.filter(d => d.date.startsWith(String(year)))}
  date="date"
  value="value"
  year={year}
  showMonthLabels
/>

Month and Day Labels

Labels orient the viewer within the grid:

// Month labels along the top
<CalendarChart
  data={data}
  date="date"
  value="value"
  showMonthLabels
/>
 
// Day-of-week labels on the left (Mon, Wed, Fri)
<CalendarChart
  data={data}
  date="date"
  value="value"
  showDayLabels
/>
 
// Both
<CalendarChart
  data={data}
  date="date"
  value="value"
  showMonthLabels
  showDayLabels
/>

Day labels typically show abbreviated names for Monday, Wednesday, and Friday to avoid crowding.


Cell Sizing

Adjust cell size and gap to control density:

// Compact (small cells, tight gaps)
<CalendarChart data={data} date="date" value="value" cellSize={8} cellGap={1} />
 
// Standard (default)
<CalendarChart data={data} date="date" value="value" cellSize={12} cellGap={2} />
 
// Large (bigger cells, more breathing room)
<CalendarChart data={data} date="date" value="value" cellSize={16} cellGap={3} />

Smaller cells work well in sidebar widgets. Larger cells are better for full-page views where individual days need to be clickable.


Accessibility

  • Each cell has an aria-label with the date and value
  • Keyboard navigation moves between cells by day, with week-jumping via up/down arrows
  • Screen readers announce the date and value for each cell
  • The empty color is distinct enough to differentiate no-data days from low-value days

Real-World Examples

GitHub-style contribution grid

<CalendarChart
  data={commits}
  date="date"
  value="count"
  year={2025}
  colorScale={["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"]}
  cellSize={11}
  cellGap={2}
  showMonthLabels
  showDayLabels
  emptyColor="#ebedf0"
  className="w-full"
/>

Exercise tracking

<CalendarChart
  data={workouts}
  date="date"
  value="minutes"
  year={2025}
  colorScale={["#fef3c7", "#fbbf24", "#f59e0b", "#d97706"]}
  showMonthLabels
  showDayLabels
  cellSize={14}
/>

Revenue by day

<CalendarChart
  data={dailyRevenue}
  date="date"
  value="revenue"
  year={2025}
  colorScale={["#dbeafe", "#60a5fa", "#2563eb", "#1e3a8a"]}
  showMonthLabels
  cellSize={12}
  cellGap={2}
  className="w-full"
/>

Other Charts