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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@danielwh2/contribution-graph

v1.0.18

Published

Framework-agnostic GitHub-style contribution heatmap for any app.

Readme

contribution-graph

Framework-agnostic GitHub-style contribution heatmap for any app.

Render a year of activity into any element as a crisp SVG or HTML grid — week columns, day rows, month labels, weekday labels, intensity colors, smooth slot-text tooltips, custom cell colors, and click handlers.

📦 Install

npm install @danielwh2/contribution-graph
pnpm add @danielwh2/contribution-graph
bun add @danielwh2/contribution-graph
yarn add @danielwh2/contribution-graph

🚀 Quick start

import "@danielwh2/contribution-graph/style.css";
import { contributionGraph } from "@danielwh2/contribution-graph";

const data = [
  { date: "2026-06-01", count: 3 },
  { date: "2026-06-02", count: 7 },
  // ...one entry per day with contributions
];

const graph = contributionGraph(document.querySelector("#graph")!, data, {
  until: "2026-06-22",
  onCellClick: (day) => console.log(day.date, day.count),
});

graph.set(newData); // update
graph.destroy();    // clean up

Import the CSS once, pass your data, get a heatmap. That's it.

🧩 API

interface ContributionDay {
  date: string;   // YYYY-MM-DD
  count: number;
  color?: string; // optional per-cell color override
}

interface ContributionGraphController {
  readonly element: HTMLElement;
  set(data: ContributionDay[], options?: ContributionGraphOptions): void;
  destroy(): void;
}

function contributionGraph(
  element: HTMLElement,
  data: ContributionDay[],
  options?: ContributionGraphOptions,
): ContributionGraphController;

| Method | What it does | | --- | --- | | set(data, options?) | Re-render with new data and/or options | | destroy() | Remove the graph and clean up listeners |

⚛️ React

import "@danielwh2/contribution-graph/style.css";
import { ContributionGraph } from "@danielwh2/contribution-graph/react";

<ContributionGraph
  data={data}
  options={{ until: "2026-06-22", onCellClick: (day) => alert(day.date) }}
/>

💚 Vue

<script setup lang="ts">
import "@danielwh2/contribution-graph/style.css";
import { ContributionGraph } from "@danielwh2/contribution-graph/vue";
</script>

<template>
  <ContributionGraph :data="data" :options="{ until: '2026-06-22' }" />
</template>

🔷 Solid

import "@danielwh2/contribution-graph/style.css";
import { contributionGraph } from "@danielwh2/contribution-graph/solid";

<div use:contributionGraph={{ data, options: { until: "2026-06-22" } }} />

🧡 Svelte

<script lang="ts">
  import "@danielwh2/contribution-graph/style.css";
  import { contributionGraph } from "@danielwh2/contribution-graph/svelte";
</script>

<div use:contributionGraph={{ data, options: { until: "2026-06-22" } }} />

⚙️ Options

| Option | Default | Description | | --- | --- | --- | | weeks | 53 | Number of week columns | | cellSize | 11 | Cell size in px | | cellGap | 3 | Gap between cells in px | | cellRadius | 3 | Cell corner radius in px | | colors | GitHub greens | Colors from least to most active (length = levels) | | levels | 5 | Intensity levels including the empty level | | showLabels | true | Show month and weekday labels | | labelColor | #8b949e | Label text color | | labelFontSize | 11 | Label font size in px | | until | today (UTC) | End date of the range, Date or YYYY-MM-DD | | tooltip | — | (day) => string \| null for smooth popup tooltips | | onCellClick | — | (day) => voidday has date, count, level | | showCounts | false | Use HTML cells. Pair with countFontSize to show in-cell counts | | countColors | auto-contrasted | Text colors per level for in-cell count labels | | countFontSize | 0 | Count label font size in px. 0 hides in-cell counts | | monthLabels | ["Jan", "Feb", ...] | Array of 12 month labels. Use "" to hide a month | | weekdayLabels | ["Mon", "", "Wed", ...] | Array of 7 weekday labels (Mon..Sun). Use "" to hide a row | | weekStart | 1 | First day of each column: 0 = Sunday, 1 = Monday | | hud | false | Wrap the graph in the cinematic "GIT COMMITS" HUD (see below) | | profile | false | Wrap the graph in a sleek luxury GitHub profile widget (see below) |

💎 Profile mode (Luxury)

Set profile: { username: "yourname" } to wrap the component in a stunning dark-mode GitHub profile card. It mimics the classic GitHub UI but elevates it with a deep #0d1117 background, floating drop shadows, a smooth glowing effect on the activity cells, and a bold activity count.

import "@danielwh2/contribution-graph/style.css";

contributionGraph(el, data, {
  profile: { username: "zzzzshawn" },
  until: "2026-06-22"
});

🛰️ HUD mode

Set hud: true to render the graph inside a cinematic heads-up display: a corner-bracketed glass panel over an animated teal→ember glitch backdrop, with auto-computed week stats and commit streak rolling in via slot-text.

import "@danielwh2/contribution-graph/style.css";
import "slot-text/style.css"; // required — powers the rolling numbers

contributionGraph(el, data, { hud: true, until: "2026-06-22" });

The HUD derives everything it shows straight from your data — this week and last week totals, the delta %, and the current day streak (with delta coloring: green when up, amber when down). It applies its own monochrome, Sunday-first, single-letter-weekday defaults; any explicit option above still overrides them (e.g. pass colors for a different ramp, or cellSize). The whole HUD is scoped inside the host element, so size and place it like any other block.

🎨 Custom colors

contributionGraph(el, data, {
  colors: ["#ebedf0", "#c6e48b", "#7bc96f", "#239a3b", "#196127"],
  levels: 5,
});

Any palette works — pass 5 colors for 5 levels, 4 for 4, etc. The first color is always the "no contributions" color.

To override the color of individual specific cells, pass a color string in your data:

const data = [
  { date: "2026-06-21", count: 12 },
  { date: "2026-06-22", count: 50, color: "#ff0000" }, // specific override
];

GitHub contribution data

GitHub's contribution calendar is available through the official GraphQL API. Use the exported helper to fetch and normalize it into ContributionDay[]:

import { contributionGraph, fetchGitHubContributions } from "@danielwh2/contribution-graph";

const result = await fetchGitHubContributions({
  username: "octocat",
  token: process.env.GITHUB_TOKEN,
  from: "2026-01-01",
  to: "2026-12-31",
});

contributionGraph(el, result.data, {
  until: result.to,
});

For browser apps, do not ship a GitHub token to users. Call fetchGitHubContributions() from your server with token, or call a safe server proxy from the browser with endpoint and no token. The helper only sends token to GitHub's official GraphQL endpoint:

const result = await fetchGitHubContributions({
  username: "octocat",
  endpoint: "/api/github-contributions",
});

If you want to preserve GitHub's per-day colors instead of using your palette, set includeGitHubColors: true.

💬 Tooltips

contributionGraph(el, data, {
  tooltip: (day) =>
    day.count === 0
      ? `No contributions on ${day.dateLabel}`
      : `${day.count} contributions on ${day.dateLabel}`,
});

Each day carries date (raw YYYY-MM-DD), count, level, and dateLabel — a human-readable UTC date produced with dayjs (e.g. Jun 22, 2026). Return null to disable the tooltip for a given day.

🖱️ Click handling

contributionGraph(el, data, {
  onCellClick: (day) => {
    console.log(day.date, day.dateLabel, day.count, day.level);
  },
});

🔢 HTML mode and optional count labels

Set showCounts: true to render cells as HTML elements instead of SVG. Counts stay hidden by default for compact graphs. Add countFontSize to show animated in-cell count labels powered by slot-text.

import "@danielwh2/contribution-graph/style.css";
import "slot-text/style.css";
import { contributionGraph } from "@danielwh2/contribution-graph";

const graph = contributionGraph(el, data, {
  showCounts: true,
  countFontSize: 9,
  until: "2026-06-22",
});

graph.set(newData);

Text colors auto-contrast with the cell background. Override with countColors:

contributionGraph(el, data, {
  showCounts: true,
  countFontSize: 9,
  colors: ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"],
  countColors: ["#57606a", "#1f2328", "#1f2328", "#ffffff", "#ffffff"],
});

📅 Date handling

All date math uses UTC so graphs render identically in every timezone. Weeks start on Sunday (GitHub convention). The range ends at until and is snapped back so the first column begins on a Sunday. Days beyond until in the final week are omitted.

Data entries are matched by YYYY-MM-DD; days with no entry default to count 0. Human-readable labels (tooltip/click day.dateLabel) are formatted with dayjs in UTC mode via the exported formatHumanDate helper.

📝 Notes

  • Browser-only DOM utility with no framework runtime dependency.
  • Smooth tooltips and optional in-cell count labels are powered by slot-text.
  • React, Vue, Solid, and Svelte are optional peer dependencies — plain JS users don't need them.
  • Import @danielwh2/contribution-graph/style.css once before rendering. Import slot-text/style.css when you use the animated tooltip or count label styles.
  • Low-level helpers also exported: buildGraph, clearGraph, buildHtmlGraph, clearHtmlGraph, buildHudGraph, clearHudGraph, computeGrid, levelForCount, parseDate, formatDate, formatHumanDate, resolveOptions, fetchGitHubContributions.

License

MIT