@zhongyao/heatmap
v0.0.6
Published
A flexible and customizable React heatmap component for displaying year-based contribution calendars
Downloads
513
Maintainers
Readme
@zhongyao/heatmap
A flexible and customizable React heatmap component for displaying year-based contribution calendars, similar to GitHub's contribution graph.

Features
- Flexible Year Display: Show any year's calendar in a heatmap format
- Customizable Week Start: Choose between Sunday or Monday as the first day of the week
- Fully Customizable Rendering: Override default rendering for day cells, month labels, and weekday labels
- Responsive Sizing: Configure cell size and gaps to fit your design
- TypeScript Support: Full TypeScript definitions included
- Lightweight: Built with React and dayjs
Installation
npm install @zhongyao/heatmapPeer Dependencies
This package requires the following peer dependencies:
{
"react": "^16.18.0",
"dayjs": "^1.11.19"
}Basic Usage
import { Heatmap } from "@zhongyao/heatmap";
function App() {
return <Heatmap year={2025} weekStartDay="sunday" />;
}Props
HeatmapProps
| Prop | Type | Default | Description |
| -------------------- | ----------------------------------------------- | ----------- | -------------------------------------------- |
| year | number | 2025 | The year to display |
| weekStartDay | 'sunday' \| 'monday' | 'sunday' | First day of the week |
| cellSize | number | 16 | Base size of cells and labels in pixels |
| gap | number | 4 | Spacing between cells and labels in pixels |
| containerGap | number | 18 | Gap between weekday labels and the main grid |
| className | string | '' | Additional className for the wrapper |
| renderDay | (props: DayCellProps) => React.ReactNode | undefined | Custom day cell renderer |
| renderMonth | (props: MonthLabelProps) => React.ReactNode | undefined | Custom month label renderer |
| renderWeekday | (props: WeekdayLabelProps) => React.ReactNode | undefined | Custom weekday label renderer |
| weekDayLabelLayout | 'left' \| 'center' \| 'right' | 'left' | Alignment of weekday labels |
| weekDayLabelStyle | CSSProperties | undefined | Custom styles for weekday labels |
Custom Rendering
Custom Day Cell
The renderDay prop allows you to customize how each day cell is rendered. You receive a DayCellProps object:
interface DayCellProps {
date: Dayjs | null; // Date object (null for empty placeholders)
dayOfYear: number | null; // Day of year (1-366, null for placeholders)
colIndex: number; // 0-indexed column
rowIndex: number; // 0-indexed row (0-6)
isEmpty: boolean; // True for year start/end placeholders
}Example:
<Heatmap
year={2025}
renderDay={({ date, isEmpty }) => {
if (isEmpty) return <div style={{ width: 16, height: 16 }} />;
// Custom logic based on your data
const contribution = getContributionCount(date);
const intensity = Math.min(contribution / 10, 1);
return (
<div
style={{
width: 16,
height: 16,
backgroundColor: `rgba(0, 255, 0, ${intensity})`,
borderRadius: 2,
}}
title={`${date.format("YYYY-MM-DD")}: ${contribution} contributions`}
/>
);
}}
/>Custom Month Label
The renderMonth prop customizes month labels:
interface MonthLabelProps {
index: number; // 0-indexed month (0-11)
label: string; // Default label (e.g., "Jan")
startCol: number; // 1-indexed starting column
span: number; // Number of columns this month spans
}Example:
<Heatmap
year={2025}
renderMonth={({ label, span }) => (
<div
style={{
gridColumn: `span ${span}`,
height: 16,
display: "flex",
alignItems: "center",
fontWeight: "bold",
fontSize: 14,
}}
>
{label}
</div>
)}
/>Custom Weekday Label
The renderWeekday prop customizes weekday labels:
interface WeekdayLabelProps {
index: number; // 0-indexed weekday (0-6)
label: string; // Default label (e.g., "Mon")
layout?: "left" | "center" | "right"; // Label alignment
style?: CSSProperties; // Custom styles
}Example:
<Heatmap
year={2025}
weekDayLabelLayout="center"
renderWeekday={({ label }) => (
<div
style={{
height: 16,
display: "flex",
alignItems: "center",
justifyContent: "center",
fontWeight: 600,
color: "#374151",
}}
>
{label.charAt(0)} {/* Show only first letter */}
</div>
)}
/>Advanced Example
Here's a complete example with custom styling and data:
import { Heatmap, DayCellProps } from "@zhongyao/heatmap";
import { Dayjs } from "dayjs";
// Your contribution data
const contributions: Record<string, number> = {
"2025-01-15": 5,
"2025-01-16": 12,
"2025-02-01": 8,
// ... more data
};
function ContributionHeatmap() {
const renderDay = ({ date, isEmpty }: DayCellProps) => {
if (isEmpty) {
return <div style={{ width: 12, height: 12 }} />;
}
const dateKey = date!.format("YYYY-MM-DD");
const count = contributions[dateKey] || 0;
// Calculate color intensity
const getColor = (count: number) => {
if (count === 0) return "#ebedf0";
if (count < 5) return "#9be9a8";
if (count < 10) return "#40c463";
if (count < 15) return "#30a14e";
return "#216e39";
};
return (
<div
style={{
width: 12,
height: 12,
backgroundColor: getColor(count),
borderRadius: 2,
cursor: "pointer",
}}
title={`${dateKey}: ${count} contributions`}
/>
);
};
return (
<Heatmap
year={2025}
weekStartDay="monday"
cellSize={12}
gap={3}
renderDay={renderDay}
className="my-heatmap"
/>
);
}Styling
The component uses Tailwind CSS classes by default, but you can fully customize styling through:
- Props: Use
cellSize,gap,containerGapfor spacing - Custom Renderers: Full control over rendering via
renderDay,renderMonth,renderWeekday - CSS Classes: Add custom classes via the
classNameprop
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
