Bankk roll

Contribution Graph

Component 9

About

A composable, customizable contribution graph component inspired by GitHub's activity heatmap. Features composable subcomponents (Grid, Tooltip, Legend), CSS variable theming, configurable cell sizes, interactive tooltips with custom render functions, and full dark mode support.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Contribution Graph to your project and fits it to your theme.

Code

How Contribution Graph is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

// GitHub contribution graph replica

import {
  ContributionGraph,
  ContributionGraphGrid,
  ContributionGraphTooltip,
  ContributionGraphLegend,
  type ContributionData,
} from "@/components/ui/contribution-graph";

function generateSampleData(): ContributionData[] {
  const data: ContributionData[] = [];
  const endDate = new Date();
  const startDate = new Date();
  startDate.setFullYear(startDate.getFullYear() - 1);

  const current = new Date(startDate);
  while (current <= endDate) {
    const dayOfWeek = current.getDay();
    const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
    const baseChance = isWeekend ? 0.3 : 0.6;

    if (Math.random() < baseChance) {
      data.push({
        date: current.toISOString().split("T")[0],
        count: Math.floor(Math.random() * 12) + 1,
      });
    }
    current.setDate(current.getDate() + 1);
  }
  return data;
}

const sampleData = generateSampleData();
const endDate = new Date();
const startDate = new Date();
startDate.setFullYear(startDate.getFullYear() - 1);
startDate.setDate(startDate.getDate() + 1);

const totalContributions = sampleData.reduce((sum, d) => sum + d.count, 0);

export default function DemoGitHub() {
  return (
    <div className="w-full max-w-4xl p-6 space-y-2">
      {/* GitHub header style */}
      <div className="text-sm text-muted-foreground">
        <span className="font-semibold text-foreground">
          {totalContributions.toLocaleString()} contributions
        </span>{" "}
        in the last year
      </div>

      {/* GitHub exact colors */}
      <div
        style={
          {
            // GitHub's exact green colors (light mode)
            "--contribution-empty": "#ebedf0",
            "--contribution-level-1": "#9be9a8",
            "--contribution-level-2": "#40c463",
            "--contribution-level-3": "#30a14e",
            "--contribution-level-4": "#216e39",
          } as React.CSSProperties
        }
        className="dark:hidden"
      >
        <ContributionGraph
          data={sampleData}
          startDate={startDate.toISOString().split("T")[0]}
          endDate={endDate.toISOString().split("T")[0]}
          cellSize={10}
          cellRadius={2}
          gap={3}
          formatCount={(count) => {
            if (count === 0) return "No contributions";
            return `${count} contribution${count !== 1 ? "s" : ""}`;
          }}
          formatDate={(date) => {
            return new Date(date).toLocaleDateString("en-US", {
              month: "long",
              day: "numeric",
              year: "numeric",
            });
          }}
        >
          <ContributionGraphGrid />
          <ContributionGraphTooltip />
          <div className="mt-2 flex items-center justify-between text-xs text-muted-foreground">
            <a href="#" className="hover:text-primary">
              Learn how we count contributions
            </a>
            <ContributionGraphLegend lessLabel="Less" moreLabel="More" />
          </div>
        </ContributionGraph>
      </div>

      {/* GitHub dark mode colors */}
      <div
        style={
          {
            // GitHub's exact green colors (dark mode)
            "--contribution-empty": "#161b22",
            "--contribution-level-1": "#0e4429",
            "--contribution-level-2": "#006d32",
            "--contribution-level-3": "#26a641",
            "--contribution-level-4": "#39d353",
          } as React.CSSProperties
        }
        className="hidden dark:block"
      >
        <ContributionGraph
          data={sampleData}
          startDate={startDate.toISOString().split("T")[0]}
          endDate={endDate.toISOString().split("T")[0]}
          cellSize={10}
          cellRadius={2}
          gap={3}
          formatCount={(count) => {
            if (count === 0) return "No contributions";
            return `${count} contribution${count !== 1 ? "s" : ""}`;
          }}
          formatDate={(date) => {
            return new Date(date).toLocaleDateString("en-US", {
              month: "long",
              day: "numeric",
              year: "numeric",
            });
          }}
        >
          <ContributionGraphGrid />
          <ContributionGraphTooltip />
          <div className="mt-2 flex items-center justify-between text-xs text-muted-foreground">
            <a href="#" className="hover:text-primary">
              Learn how we count contributions
            </a>
            <ContributionGraphLegend lessLabel="Less" moreLabel="More" />
          </div>
        </ContributionGraph>
      </div>
    </div>
  );
}

More by Bankk roll

View all
  • Animated Testimonials

    Animated Testimonials

    1.1K
  • Commerce Hero

    Commerce Hero

    660
  • Acme Hero

    Acme Hero

    443
  • Myna Hero

    Myna Hero

    384
  • Single Pricing Card

    Single Pricing Card

    306
  • Pricing Card

    Pricing Card

    287
  • File Viewer

    File Viewer

    177
  • Code Editor Sheet

    Code Editor Sheet

    142