npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@zhongyao/heatmap

v0.0.6

Published

A flexible and customizable React heatmap component for displaying year-based contribution calendars

Downloads

513

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/heatmap

Peer 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:

  1. Props: Use cellSize, gap, containerGap for spacing
  2. Custom Renderers: Full control over rendering via renderDay, renderMonth, renderWeekday
  3. CSS Classes: Add custom classes via the className prop

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.