# React GitHub Contribution Graph: Daten, Themes und A11y

> Bau einen React GitHub Contribution Graph aus einem Username oder eigenen Daten, dazu eine Activity Heatmap mit Tastaturbedienung und Farben für beide Themes.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 19. Okt. 2026
- Kategorie: [Komponenten-Guides](https://wingo-ui.com/de/blog/category/components)
- Lesezeit: 9 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/react-github-contribution-graph
- Englische Fassung: https://wingo-ui.com/blog/react-github-contribution-graph

## Kurz gesagt

Für ein Portfolio oder eine Profilseite rendert die kostenlose GitHub Activity von Wingo UI einen React GitHub Contribution Graph aus einem Username oder aus Daten, die du auf dem Server lädst, und passt die Wochen an den Bildschirm an, damit nichts seitlich scrollt. Für deine eigenen Produktdaten (Bestellungen, Workouts, CRM-Aktivität) bringt der Pro Heatmap Calendar Tastaturnavigation, ein gesprochenes Label pro Tag, eine Tabelle für Screenreader und eine Skala in einem einzigen Farbton, die in Light und Dark Mode lesbar bleibt.

Du willst einen React GitHub Contribution Graph in deinem Portfolio, einer „Über mich“-Seite oder einem Entwicklerprofil: das bekannte Raster aus grünen Quadraten, eins pro Tag, mit der Jahressumme darüber. Oder du willst dieselbe Form für deine eigenen Daten, etwa Bestellungen pro Tag, Team-Aktivität im CRM oder Trainingsserien. Im ersten Fall geht es vor allem darum, woher die Daten kommen. Im zweiten um Skalen, Labels und Tastaturzugang, denn ein Raster aus bunten Quadraten sagt einem Screenreader gar nichts. Dieser Guide deckt beides mit zwei Komponenten von Wingo UI ab: der kostenlosen [GitHub Activity](https://wingo-ui.com/components/github-activity) und dem Pro [Heatmap Calendar](https://wingo-ui.com/components/heatmap-calendar).

## Welche React-Pakete für Contribution Graphs gibt es?

Drei etablierte npm-Pakete zeichnen dieses Raster: react-activity-calendar, react-github-calendar und react-calendar-heatmap, alle unter MIT-Lizenz. Die Versionen stammen aus der npm-Registry, Stand 19. Oktober 2026.

| Paket | Version | Was es macht | Hinweise aus der README |
|---|---|---|---|
| [react-activity-calendar](https://github.com/grubersjoe/react-activity-calendar) | 3.2.1 | Zeichnet das Raster aus `{ date, count, level }`-Daten | Beliebig viele Levels (auch negative), Farbthemes, Dark und Light Mode, Tooltips, Lokalisierung, SSR wird unterstützt |
| [react-github-calendar](https://github.com/grubersjoe/react-github-calendar) | 5.0.9 | Nimmt einen `username` und lädt den Kalender | Lädt im Browser, laut README rendert es deshalb nicht auf dem Server; für SSR verweist es auf react-activity-calendar |
| [react-calendar-heatmap](https://github.com/kevinsqi/react-calendar-heatmap) | 1.10.0 | SVG-Heatmap aus `{ date, count }` | Du ordnest Werte mit `classForValue` CSS-Klassen zu und stylst sie selbst; Tooltips über `titleForValue` oder Data-Attribute |

Keine der drei READMEs erwähnt Tastaturnavigation oder Ausgabe für Screenreader (geprüft am 19. Oktober 2026). Wenn du ein fertiges Widget willst und damit leben kannst, ist react-activity-calendar das vollständigste. Wenn du Quellcode willst, den du ändern kannst, mit denselben Props, demselben Theming und derselben Motion wie der Rest deiner UI, lassen sich die beiden Komponenten unten direkt nach `components/ui` installieren.

## Wie kann ich in React einen GitHub Contribution Graph einbinden?

Installier GitHub Activity mit der CLI und gib ihr einen GitHub-Username:

```bash
npx wingo-ui@latest add github-activity
```

```tsx
import GitHubActivity from "@/components/ui/github-activity";

export function Profile() {
  return <GitHubActivity username="octocat" showMonths />;
}
```

Mit einem `username` lädt die Komponente zwei Dinge im Browser. Der Kalender kommt von [github-contributions-api](https://github.com/grubersjoe/github-contributions-api), einem kostenlosen Dienst, der die öffentliche Profilseite ausliest; laut README werden Ergebnisse eine Stunde lang gecacht, und nicht gecachte Requests sind auf 10 pro 10 Sekunden und IP begrenzt. Die Top-Repositories im Footer kommen vom öffentlichen Events-Endpoint von GitHub, der nur [Events der letzten 30 Tage und höchstens 300 davon](https://docs.github.com/en/rest/activity/events) liefert, und nicht authentifizierte REST-Aufrufe sind auf [60 Requests pro Stunde](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api) begrenzt. Für eine persönliche Seite reicht das; für alles mit echtem Traffic lädst du die Daten auf dem Server (nächster Abschnitt).

Ein ungültiger oder unbekannter Login zeigt „No public activity found for {login}“ (das Template `notFoundLabel`, mit eingesetztem Login) und ruft `onError` auf, damit du auf gespeicherte Daten ausweichen kannst.

Die Demo unten nutzt das Beispieljahr, das mit der Doku mitgeliefert wird. Es geht also kein Request an GitHub.

> Live-Demo (GitHub Activity): Fahr mit der Maus über ein Quadrat oder tipp auf einem Touchscreen darauf, um Anzahl und Datum zu sehen. Klick auf den Chevron, um die Top-Repositories über dem Raster aufzuklappen, und noch einmal, um sie wieder einzuklappen. Probier sie unter [GitHub Activity](https://wingo-ui.com/components/github-activity) aus und installier sie mit `npx wingo-ui@latest add github-activity`.

## Wie rendere ich den Contribution Graph auf dem Server?

Hol den Kalender in einer Server Component über die GraphQL API von GitHub und übergib ihn als `contributions`. Wenn du die Daten übergibst und keinen `username`, wird im Browser nichts geladen, der Token bleibt auf dem Server, und schon das erste HTML enthält die richtige Summe. Die [GraphQL-Referenz](https://docs.github.com/en/graphql/reference/users) beschreibt `contributionCalendar.weeks[].contributionDays[]` mit einem `date`, einem `contributionCount` und einem `contributionLevel` von `NONE` bis `FOURTH_QUARTILE`; ohne `from` und `to` deckt die Collection das letzte Jahr ab.

```tsx
import GitHubActivity, { type Contribution, type ContributionLevel } from "@/components/ui/github-activity";

const LEVELS: Record<string, ContributionLevel> = {
  NONE: 0,
  FIRST_QUARTILE: 1,
  SECOND_QUARTILE: 2,
  THIRD_QUARTILE: 3,
  FOURTH_QUARTILE: 4,
};

const QUERY = `query ($login: String!) {
  user(login: $login) {
    contributionsCollection {
      contributionCalendar {
        weeks { contributionDays { date contributionCount contributionLevel } }
      }
    }
  }
}`;

type Day = { date: string; contributionCount: number; contributionLevel: string };

async function getContributions(login: string): Promise<Contribution[]> {
  const res = await fetch("https://api.github.com/graphql", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: QUERY, variables: { login } }),
    cache: "force-cache",
    next: { revalidate: 3600 },
  });
  if (!res.ok) return [];

  const json = await res.json();
  const weeks: { contributionDays: Day[] }[] =
    json.data?.user?.contributionsCollection.contributionCalendar.weeks ?? [];
  const days = weeks.flatMap((week) => week.contributionDays);
  // eine spalte pro woche, also müssen die daten an einem sonntag beginnen
  const start = days.findIndex((day) => new Date(`${day.date}T00:00:00Z`).getUTCDay() === 0);

  return days.slice(Math.max(0, start)).map((day) => ({
    date: day.date,
    count: day.contributionCount,
    level: LEVELS[day.contributionLevel] ?? 0,
  }));
}

export async function Contributions() {
  const contributions = await getContributions("your-login");
  if (contributions.length === 0) return null;

  return <GitHubActivity contributions={contributions} yearLabel="in the last year" showMonths className="max-w-2xl" />;
}
```

Zwei Details. Caching ist in Next.js 16 Opt-in, und `cache: "force-cache"` sorgt dafür, dass ein POST mit Authorization-Header gecacht wird ([fetch-Doku](https://nextjs.org/docs/app/api-reference/functions/fetch)); `revalidate: 3600` begrenzt die gecachte Kopie auf eine Stunde. Außerdem lautet die Überschrift standardmäßig „{count} contributions in {year}“, mit dem Jahr des neuesten Tages; für ein gleitendes Zeitfenster ist `yearLabel="in the last year"` genauer. Übergib `repos` als `{ name, count, href?, logo? }[]`, wenn du auch das Footer-Panel willst.

## Wie passe ich die Farben für Light und Dark Mode an?

Übergib die Farben über `accent`, als eine Farbe oder als Array von Abstufungen. Eine einzelne Farbe (standardmäßig `#39d353`) wird mit 30%, 52%, 76% und 100% Deckkraft über einer leeren Zelle gezeichnet, die aus der Vordergrundfarbe mit 8% Deckkraft besteht. So funktioniert derselbe Wert auf der weißen Card im Light Mode und auf der schwarzen Card im Dark Mode. Ein Array mit vier Abstufungen legt jedes Level exakt fest, fünf Abstufungen ersetzen zusätzlich die leere Farbe:

```tsx
<GitHubActivity contributions={contributions} accent={["#0e4429", "#006d32", "#26a641", "#39d353"]} />
```

Diese vier Grüntöne sind auf einen dunklen Hintergrund abgestimmt. Wenn sich deine Abstufungen je nach Theme unterscheiden, übergib CSS-Variablen und definier sie pro Theme in deinem Stylesheet, zum Beispiel `accent={["var(--commit-1)", "var(--commit-2)", "var(--commit-3)", "var(--commit-4)"]}`. Wo diese Variablen hingehören, zeigt der [Guide zum Dark Mode in Tailwind v4](https://wingo-ui.com/de/blog/tailwind-v4-dark-mode). `background`, `radius`, `cellSize` (11px), `cellRadius` (3px) und `chevronColor` decken den Rest des Looks ab.

Auf dem Smartphone zeigt das Raster so viele aktuelle Wochen, wie in die Breite der Card passen, und lässt ältere weg, damit es nie seitlich scrollt. `months` begrenzt den Zeitraum, und eine `max-w-*`-Klasse zeigt bewusst weniger Wochen.

## Wann brauche ich eine allgemeine Activity Heatmap in React?

Sobald es deine eigenen Daten sind. Ein GitHub-Graph geht davon aus, dass die Levels schon berechnet sind und der Leser nur ein Gefühl für das Jahr braucht. Eine Dashboard-Kachel mit Bestellungen, Rechnungen oder Support-Tickets pro Tag braucht mehr: eigene Schwellenwerte, eigene Begriffe in den Labels, einen ausgewählten Tag, der eine Liste steuert, und echte Zahlen für Menschen, die die Farben nicht sehen. Genau dafür ist eine Activity Heatmap React-Komponente wie der [Heatmap Calendar](https://wingo-ui.com/components/heatmap-calendar) gedacht.

```bash
npx wingo-ui@latest add heatmap-calendar
```

```tsx
"use client";

import { useState } from "react";
import { HeatmapCalendar, type HeatmapDatum } from "@/components/ui/heatmap-calendar";

export function WorkoutHeatmap({ data }: { data: HeatmapDatum[] }) {
  const [day, setDay] = useState<string | null>(null);

  return (
    <HeatmapCalendar
      data={data}
      weeks={26}
      tone="success"
      thresholds={[1, 20, 40, 60]}
      value={day}
      onValueChange={setDay}
      locale="de-DE"
      label="Trainingsminuten pro Tag"
      labels={{
        total: (n, weeks) => `${n} Minuten in den letzten ${weeks} Wochen`,
        cell: (value, date) => `${value} Minuten am ${date}`,
        empty: (date) => `Kein Training am ${date}`,
        valueName: "Minuten",
        table: "Trainingsminuten pro Monat",
      }}
    />
  );
}
```

`data` ist ein `{ date, value }` pro ISO-Tag; fehlende Tage zählen als 0, doppelte Daten werden addiert. Ohne `thresholds` kommen die Levels aus Quantilen der Werte ungleich null, also ist jede Aktivität mindestens Level 1. `endDate` ist standardmäßig das neueste Datum in deinen Daten, nie die Uhr, damit Server und Browser dasselbe Raster zeichnen. `weekStartsOn` folgt der Locale (Sonntag in `en-US`, Montag in `en-GB`), solange du es nicht setzt.

> Live-Demo (Heatmap calendar): Fahr mit der Maus über einen Tag, um seinen Wert zu sehen, klick ihn an, um ihn auszuwählen, dann spring mit Tab ins Raster und beweg dich mit den Pfeiltasten. Wechsel zwischen All, Calls, Emails und Meetings und sieh zu, wie die Farben überblenden. Probier sie unter [Heatmap calendar](https://wingo-ui.com/components/heatmap-calendar) aus und installier sie mit `npx wingo-ui@latest add heatmap-calendar`.

## Wie mache ich eine React Calendar Heatmap barrierefrei?

Mach jede Zahl auch ohne Farbe zugänglich. Das WCAG-Erfolgskriterium [1.4.1 Use of Color](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html) verlangt, dass Farbe nicht das einzige Mittel ist, um Information zu vermitteln, und genau so funktioniert eine Heatmap von Haus aus. 2018 hat Adrian Roselli [den Contributions-Chart von GitHub untersucht](https://adrianroselli.com/2018/02/github-contributions-chart.html), dabei festgestellt, dass er per Tastatur nicht bedienbar und für Screenreader unsichtbar war, und dafür plädiert, die Daten in eine Tabelle zu packen. GitHub hat [den eigenen Graphen im März 2023 nachgebessert](https://github.blog/changelog/2023-03-02-accessibility-improvements-for-the-contribution-graph/): Die Pfeiltasten springen zwischen den Tagen, und ein Screenreader liest den Graphen als Tabelle und eine Zusammenfassung jedes Tages vor.

Der Heatmap Calendar folgt demselben Modell:

- **Ein einziger Tab-Stopp.** Tab landet auf dem ausgewählten oder dem neuesten Tag. Pfeil links und rechts springen um eine Woche, Pfeil hoch und runter um einen Tag, Pos1 und Ende zum ersten und letzten Tag, Bild auf und Bild ab um vier Wochen. Enter oder Leertaste wählt aus, Esc hebt die Auswahl auf.
- **Ein gesprochenes Label pro Tag** aus `labels.cell` und `labels.empty`, mit dem Beispiel oben in `de-DE` etwa „42 Minuten am Donnerstag, 24. September 2026“. Das Datum wird für deine Locale ausgeschrieben.
- **Eine Tabelle für Screenreader** mit der Summe und den aktiven Tagen jedes Monats, beschriftet mit `label`. `description` ergänzt eine Kernaussage in einem Satz.
- **Eine Skala, die in beiden Themes lesbar ist.** Level 0 ist die Vordergrundfarbe mit 7% Deckkraft, sichtbar auf Weiß und auf der dunklen Surface. Die übrigen Levels nutzen einen einzigen Farbton von 30% bis 100% in gleichen Schritten, die Reihenfolge steckt also in der Helligkeit. Setz `tone` oder über `color` eine beliebige CSS-Farbe und mit `emptyColor` die Farbe der leeren Tage.

GitHub Activity ist hier schlanker. Ihr Raster ist ein einzelnes Bild mit der Überschrift als Namen („1234 contributions in the last year“), und der Tooltip pro Tag reagiert auf Hover und Touch, nicht auf die Tastatur. Für eine dekorative Profil-Card passt das. Wenn es auf die Tageszahlen ankommt, nimm den Heatmap Calendar.

## Wie verhält sich die Heatmap auf dem Smartphone?

Auf dem Smartphone scrollt der Heatmap Calendar das Jahr entweder als horizontale Leiste oder zeigt nur die Wochen, die hineinpassen, je nach `overflow`. `overflow="scroll"` (der Standard) macht aus dem Jahr eine horizontale Leiste, die bei der neuesten Woche startet, wochenweise einrastet, an den Rändern ausblendet und die Wochentags-Labels fixiert; vertikales Wischen scrollt weiterhin die Seite. `overflow="fit"` zeigt nur die neuesten Wochen, die hineinpassen, ohne Scrollen.

Touch hat eigene Regeln: Der erste Tap auf einen Tag heftet seinen Wert über dem Raster an (damit kein Finger ihn verdeckt), ein zweiter Tap auf denselben Tag wählt ihn aus, und ein Tap daneben hebt das auf. `tooltipMode` ist standardmäßig `"auto"`, das auf Touchscreens diese feste Anzeige nutzt und sonst eine schwebende neben dem Tag. Der Intro-Sweep und das Überblenden der Farben respektieren Reduced Motion, wie im [Guide zu prefers-reduced-motion](https://wingo-ui.com/de/blog/prefers-reduced-motion-react) erklärt.

## Was sind die typischen Fallstricke beim Contribution Graph?

Diese vier Fehler machen einen Contribution Graph auf eine Weise kaputt, die man in der Entwicklung leicht übersieht:

- **Daten, die nicht an einem Sonntag beginnen.** GitHub Activity zeichnet eine Spalte pro sieben Einträge der übergebenen `contributions` und kürzt nur ihre selbst geladenen Daten. Lass das Array an einem Sonntag beginnen, sonst verrutscht jede Spalte. Das Server-Beispiel oben schneidet die erste angebrochene Woche ab.
- **GitHub aus dem Browser jedes Besuchers aufrufen.** Die kostenlosen APIs haben Limits pro IP, und der Events-Endpoint deckt nur 30 Tage ab. Lad die Daten auf dem Server und cache sie.
- **„Heute“ während des Renderns lesen.** Der Heatmap Calendar liest das Datum des Betrachters erst nach der Hydration für den Heute-Ring und nimmt für `endDate` deine Daten. Halt das in deinen eigenen Wrappern genauso, sonst unterscheiden sich die Raster von Server und Client.
- **Eine Heatmap als einzige Ansicht einer KPI.** Kombinier sie mit einer Zahl: einer [Stat Card](https://wingo-ui.com/components/stat-card) für die Summe oder einer [Sparkline](https://wingo-ui.com/components/sparkline) für den Trend. Den Rest eines Dashboards behandelt der [Vergleich der Libraries für Dashboards](https://wingo-ui.com/de/blog/best-react-component-library-for-dashboard).

## Wie füge ich das in mein Projekt ein?

Führ `npx wingo-ui@latest add github-activity` für den kostenlosen Contribution Graph aus oder `npx wingo-ui@latest add heatmap-calendar` für die allgemeine Heatmap (Pro, siehe [Preise](https://wingo-ui.com/de/pricing)). Die CLI kopiert den Quellcode nach `components/ui` und ergänzt, was er importiert. Weitere Deep Dives zu einzelnen Komponenten findest du in der [Kategorie Komponenten-Guides](https://wingo-ui.com/de/blog/category/components), und der [Guide zu React-Formularkomponenten](https://wingo-ui.com/de/blog/react-form-components-guide) wendet dieselben Regeln für Tastatur und Screenreader auf jedes Feld an.

## Komponenten in diesem Artikel

- [GitHub Activity](https://wingo-ui.com/components/github-activity) (Free): A React GitHub contribution graph: a yearly heatmap with a panel of your top repositories. Installation: `npx wingo-ui@latest add github-activity`
- [Heatmap calendar](https://wingo-ui.com/components/heatmap-calendar) (Pro): A React heatmap calendar of activity by day over weeks or a year, on a one-hue scale with month and weekday labels, a total and a legend. Installation: `npx wingo-ui@latest add heatmap-calendar`

## Häufige Fragen

### Wie zeige ich meinen GitHub Contribution Graph in React an?

Installier eine Komponente, die das Jahresraster zeichnet, und gib ihr entweder einen Username oder die Tagesdaten. Mit Wingo UI lädt <GitHubActivity username="your-login" /> das letzte Jahr im Browser, oder du holst den Kalender auf dem Server über die GraphQL API von GitHub und übergibst ihn als contributions.

### Woher kommen die Daten für den Contribution Graph?

Die GraphQL API von GitHub liefert sie als user.contributionsCollection.contributionCalendar, mit einem Count und einem Level pro Tag; dafür brauchst du einen Token. Ohne Token rufen react-github-calendar und der Username-Modus der Wingo-UI-Komponente die kostenlose github-contributions-api auf, die die öffentliche Profilseite ausliest und Ergebnisse eine Stunde lang cacht.

### Was ist der Unterschied zwischen einem Contribution Graph und einer Calendar Heatmap?

Ein Contribution Graph ist eine Calendar Heatmap mit den Daten und dem Look von GitHub: Wochen als Spalten, Tage als Zeilen, fünf Grüntöne. Eine allgemeine React Calendar Heatmap nimmt jeden Tageswert, etwa Bestellungen oder Minuten, und lässt dich Skala, Farben und Labels selbst wählen.

### Ist eine Kalender-Heatmap barrierefrei?

Nur wenn die Zahlen auch ohne Farbe zugänglich sind. Gib jedem Tag ein Text-Label, mach das Raster per Tastatur erreichbar und biete Screenreadern eine Tabelle oder eine Zusammenfassung an, so wie GitHub es im März 2023 für den eigenen Graphen nachgerüstet hat.

### Ist die GitHub Activity von Wingo UI kostenlos?

Ja. GitHub Activity gehört zum kostenlosen Angebot und lässt sich mit npx wingo-ui@latest add github-activity installieren. Der Heatmap Calendar ist eine Pro-Komponente.

---

Quelle: https://wingo-ui.com/de/blog/react-github-contribution-graph
