# Shadcn KPI Cards: Deltas, Sparklines und Zielbalken

> So baust du shadcn KPI Cards, die zeigen, ob eine Zahl gut ist: Wert mit Count-up, ein nach Bedeutung gefärbtes Delta, Sparkline, Zielbalken und Mobile-Raster.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 6. Nov. 2026
- Kategorie: [Komponenten-Guides](https://wingo-ui.com/de/blog/category/components)
- Lesezeit: 9 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/shadcn-kpi-cards
- Englische Fassung: https://wingo-ui.com/blog/shadcn-kpi-cards

## Kurz gesagt

Eine gute shadcn KPI Card zeigt auf einen Blick, ob eine Zahl gut ist. Dafür braucht sie fünf Teile: ein klares Label, eine formatierte Zahl, ein Delta, das nach Bedeutung gefärbt ist (weniger Churn ist grün), eine Sparkline für den Verlauf des Zeitraums und einen Zielbalken für das Ziel. shadcn/ui hat keine KPI-Card-Komponente, und sein Block dashboard-01 liefert statische Karten mit fest eingetragenen Werten und einem Outline-Badge, das bei Gewinn und Verlust gleich aussieht. Stat Card, Trend Badge, Sparkline und KPI Dashboard von Wingo UI (alle Pro) regeln Formatierung, Bedeutung, Count-up und das zweispaltige Raster auf dem Smartphone über Props.

Du öffnest ein Dashboard, siehst „$128,450“ in einer Kachel und weißt immer noch nicht, ob der Monat gut lief. Genau diese Lücke lassen die meisten shadcn KPI Cards offen: eine Zahl, ein Label, vielleicht ein Badge, aber keine Richtung, kein Verlauf und kein Ziel. Dieser Guide zeigt, was eine KPI Card braucht, um die Frage „ist das gut?“ zu beantworten, was der offizielle shadcn-Block mitbringt und wie du shadcn Stat Cards mit [Stat Card](https://wingo-ui.com/components/stat-card), [Trend Badge](https://wingo-ui.com/components/trend-badge) und [Sparkline](https://wingo-ui.com/components/sparkline) von Wingo UI baust. Danach setzen wir sie in den kompletten Block [KPI Dashboard](https://wingo-ui.com/components/kpi-dashboard) und schauen uns an, wie sein Raster auf dem Smartphone zusammenklappt.

## Was sollte eine KPI Card zeigen?

Eine KPI Card hat ihren Platz verdient, wenn jemand sie in zwei Sekunden liest und weiß, was als Nächstes zu tun ist. Dafür braucht sie fünf Teile, und jeder beantwortet eine kleinere Frage:

1. **Das Label und eine Erklärung.** Was ist das für eine Zahl? „Umsatz“ reicht; „Nettoumsatz, vor Steuern“ hinter einem Info-Icon ist besser, denn zwei Leute im selben Team meinen mit demselben Wort oft verschiedene Dinge.
2. **Die Zahl, lesbar formatiert.** `$128,450`, `2.1%`, `18 days`, `128.5K`. Das Format gehört zur Kennzahl, die Locale zu den Lesenden.
3. **Die Änderung und ihre Bedeutung.** `+12.4% vs. last month`, grün, wenn die Änderung gut ist, rot, wenn sie schlecht ist. Die Farbe muss der Bedeutung folgen, nicht dem Vorzeichen: Weniger Churn ist eine gute Nachricht.
4. **Der Verlauf des Zeitraums.** Eine Sparkline zeigt, ob ein Monat mit +12% ein stetiger Anstieg war oder eine einzige große Rechnung am letzten Tag.
5. **Das Ziel.** Ein Zielbalken („68% des Ziels“) macht aus einer Zahl einen Fortschritt.

Die meisten Karten hören nach den ersten zwei oder drei Teilen auf. Die letzten beiden machen eine Reihe React KPI Cards nützlich statt dekorativ.

## Was bringen die Dashboard-Karten von shadcn mit?

shadcn/ui hat keine KPI- oder Stat-Card-Komponente (geprüft im November 2026). Am nächsten kommt die Datei `SectionCards` im Block `dashboard-01` ([Quellcode auf GitHub](https://github.com/shadcn-ui/ui/blob/main/apps/v4/registry/new-york-v4/blocks/dashboard-01/components/section-cards.tsx), gelesen am 6. November 2026). Sie kombiniert `Card`, `CardHeader`, `CardDescription`, `CardTitle`, `CardAction`, `CardFooter` und `Badge` und ist ein guter Ausgangspunkt für ein shadcn Analytics Dashboard:

- Jede Karte hat ein Label, einen fest eingetragenen Wert wie `$1,250.00`, ein Outline-`Badge` mit Trend-Icon und einem Text wie `+12.5%` sowie einen zweizeiligen Footer („Down 20% this period“, „Acquisition needs attention“).
- Das Badge sieht bei einem Anstieg und einem Rückgang gleich aus. Nur das Icon wechselt, also ist „-20%“ bei New Customers optisch nicht als schlecht markiert.
- Es gibt keine Sparkline, kein Ziel und kein Count-up. Die Werte sind Strings im JSX, die Formatierung liegt also bei dir.
- Das Raster ist standardmäßig einspaltig, ab der Container-Breite `@xl` zweispaltig und ab `@5xl` vierspaltig.

Das ist der shadcn-Weg: ein Muster, das du kopierst und dann selbst pflegst, und Block-Sammlungen aus der Community folgen demselben Modell. Für vier feste Kacheln funktioniert das gut. Sobald die Zahlen aus einer API kommen, schreibst du die Formatierung, die Gut-oder-schlecht-Farbe pro Kennzahl und den Ladezustand selbst, und zwar in jeder Karte. Eine Komponente mit Props bündelt diese Logik an einer Stelle.

## Wie baue ich eine KPI Card mit Stat Card?

Installier `stat-card` und übergib einen numerischen `value`, ein `format`, ein `delta`, die Sparkline-Daten und ein `goal`: Ein Element deckt alle fünf Teile ab. Die CLI bringt die Abhängigkeiten gleich mit (Zähler, Fortschrittsbalken, Tooltip und Zahlen-Helfer):

```bash
npx wingo-ui@latest add stat-card
```

`value` ist eine Zahl, `format` legt fest, wie sie gelesen wird, `delta` ist die Änderung in Einheiten von `deltaFormat` (standardmäßig Prozent), und `goal` ergänzt den Fortschrittsbalken:

```tsx
import { Wallet } from "lucide-react";
import { StatCard } from "@/components/ui/stat-card";

const daily = [3900, 4100, 3800, 4500, 4700, 4200, 5100, 5300, 4900, 5600, 5800, 6100];

export function RevenueCard() {
  return (
    <StatCard
      label="Umsatz"
      info="Ausgestellte Rechnungen, vor Steuern"
      icon={<Wallet />}
      period="Sept. 2026"
      value={128450}
      format="currency"
      currency="USD"
      delta={12.4}
      deltaLabel="ggü. Vormonat"
      sparkline={daily}
      goal={190000}
      locale="en-US"
    />
  );
}
```

> Live-Demo (Stat Card): Drück auf Simulate a new day: Ein neuer Tag kommt zur Sparkline dazu, und Wert und Delta zählen von den Zahlen auf dem Bildschirm zu den neuen. Probier sie unter [Stat Card](https://wingo-ui.com/components/stat-card) aus und installier sie mit `npx wingo-ui@latest add stat-card`.

### Schadet das Count-up der SEO oder Screenreadern?

Nein, denn die Animation läuft nur im Client. Das Server-HTML und der erste Paint enthalten schon die Endzahl, ein Crawler oder ein langsames Smartphone sieht also `$128,450` und nicht `$0`. Die Zahl zählt einmal von null hoch, wenn die Karte zum ersten Mal ins Bild scrollt (standardmäßig 900ms, einstellbar mit `duration`), und spätere Änderungen zählen von der Zahl auf dem Bildschirm aus. Screenreader hören einen einzigen Satz mit Endwert und Änderung, etwa „$128,450, up 12.4% vs. last month“, nie die Zahlen dazwischen. Bei reduzierter Bewegung erscheinen Zahlen und Charts sofort im Endzustand. Für Live-Zahlen, die laufend ticken, nutzt `animation="roll"` stattdessen ein Zählwerk, und `animation="none"` schaltet die Animation ab.

### Woher weiß das Delta, was gut und was schlecht ist?

Der Pfeil folgt dem Vorzeichen von `delta`, die Farbe der Bedeutung. Standardmäßig ist ein Anstieg grün und ein Rückgang rot. Setz `invertTrend` für Kennzahlen, bei denen weniger besser ist, etwa Kosten, Churn oder Antwortzeit: Ein Rückgang wird grün, und der Pfeil zeigt trotzdem nach unten. Die Prop `tone` färbt die Icon-Kachel, die Sparkline und den Zielbalken, aber nie das Delta. So kann eine Karte in Markenorange schlechte Nachrichten nicht aus Versehen neutral aussehen lassen.

Dieselbe Logik gibt es als eigene Komponente, `TrendBadge`, für Tabellenzellen, Ranglisten und deine eigenen Karten:

```tsx
"use client";

import { TrendBadge } from "@/components/ui/trend-badge";

export function ChangeCells() {
  return (
    <>
      <TrendBadge value={12.4} label="ggü. Vormonat" locale="en-US" />
      <TrendBadge value={-0.4} invertTrend formatValue={(v) => `${v < 0 ? "−" : "+"}${Math.abs(v)} Pkt.`} />
    </>
  );
}
```

Die Datei braucht `"use client"`, weil `formatValue` eine Funktion ist, und Funktionen können nicht als Props von einer Server Component in eine Client Component wandern.

> Live-Demo (Trend badge): Drück auf Change, um durch die Werte zu gehen: Mit invertTrend wird ein Anstieg rot und ein Rückgang grün, während der Pfeil weiter in die echte Richtung zeigt. Probier sie unter [Trend badge](https://wingo-ui.com/components/trend-badge) aus und installier sie mit `npx wingo-ui@latest add trend-badge`.

### Wann nutze ich die eigenständige Sparkline?

Nimm die eigenständige, wenn jemand die einzelnen Punkte ansehen muss oder wenn der Chart außerhalb einer Karte steht. Stat Card hat eine eingebaute Sparkline (`sparkline` für die Daten, `sparklineType` für `line`, `area` oder `bar`), und `stat-card.tsx` exportiert diesen Chart für einfache Fälle auch als `Sparkline`. Die separate Komponente [Sparkline](https://wingo-ui.com/components/sparkline) geht weiter: Gewinn-/Verlust-Striche (`type="win-loss"`), Markierungen für Minimum und Maximum (`showMinMax`), eine gestrichelte `reference`-Linie beim ersten Wert, beim Durchschnitt oder bei null, `trendColor` zum Färben nach Richtung und der Modus `interactive`, in dem du mit der Maus darüberfährst, einen Finger darüberziehst oder mit den Pfeiltasten jeden Punkt abliest. Setz sie in Tabellenzeilen ein, oder gib sie über die Prop `chart` an eine Karte, wenn du diese Extras brauchst:

```tsx
import { Sparkline } from "@/components/ui/sparkline";

export function RevenueTrend() {
  return (
    <Sparkline
      data={[8200, 8650, 8400, 9100, 9480, 10150, 10600, 11420, 12480]}
      valueFormat="currency"
      label="Umsatz, letzte 9 Wochen"
      trendColor
      interactive
      locale="en-US"
    />
  );
}
```

Beide Dateien exportieren eine Komponente namens `Sparkline`. Importier die eigenständige also aus `@/components/ui/sparkline` und gib ihr einen Alias, wenn eine Datei beide braucht.

## Wie ordne ich eine Reihe React KPI Cards an?

Pack die Karten in `StatGroup`. Das ist eine Liste (`role="list"`) mit responsiven Spalten: standardmäßig zwei auf dem Smartphone und vier ab 1024px, änderbar mit `columns={{ base, sm, lg }}`. Die Kacheln zählen im Abstand von 60ms hoch (abschaltbar mit `stagger={false}`), und `variant="joined"` zeichnet statt einzelner Karten ein Panel mit feinen Linien zwischen den Kacheln.

```tsx
"use client";

import { Clock, Repeat, UserMinus, Users } from "lucide-react";
import { StatCard, StatGroup } from "@/components/ui/stat-card";

export function SaasKpis({ mrr, active }: { mrr: number[]; active: number[] }) {
  return (
    <StatGroup variant="joined">
      <StatCard label="MRR" icon={<Repeat />} value={42800} format="currency" delta={6.2} sparkline={mrr} goal={50000} locale="en-US" />
      <StatCard label="Aktive Nutzer" icon={<Users />} value={3214} delta={4.8} sparkline={active} locale="en-US" />
      <StatCard
        label="Churn"
        icon={<UserMinus />}
        value={2.1}
        format="percent"
        delta={-0.4}
        formatDelta={(d) => `${d} Pkt.`}
        invertTrend
        locale="en-US"
      />
      <StatCard
        label="Erste Antwortzeit"
        icon={<Clock />}
        value={4 * 3600}
        format="duration"
        delta={-1800}
        deltaFormat="duration"
        invertTrend
        locale="en-US"
      />
    </StatGroup>
  );
}
```

Drei Details in diesem Code sind wichtig. Die Datei ist eine Client Component, weil `formatDelta` eine Funktions-Prop ist. Churn nutzt `formatDelta`, weil die Änderung eines Prozentwerts in Prozentpunkten gemessen wird, nicht in Prozent: Von 2.5% auf 2.1% sind „−0.4 Pkt.“, und „−0.4%“ wäre falsch. Dauern werden in Sekunden übergeben, also gibt `format="duration"` `4 hr` aus und das Delta `30 min`. Übergib `loading`, solange die Daten unterwegs sind: Jede Karte zeigt dann Skeletons in den echten Größen, und nichts springt, wenn die Zahlen ankommen.

## Wie sieht ein komplettes React KPI Dashboard aus?

Ein komplettes Dashboard setzt die KPI-Kacheln nach oben und die Widgets darunter, und der Block [KPI Dashboard](https://wingo-ui.com/components/kpi-dashboard) liefert genau diesen ganzen Screen: Umsatz im Vergleich zum Vorzeitraum, Umsatz nach Monat oder Stadt, Quellen, einen Funnel, Top-Seller, die letzten Rechnungen und einen Aktivitäts-Feed. Im Header sitzen eine Zeitraumauswahl mit Presets und ein Vergleichsschalter, der die gestrichelte Vorperiode und jedes Delta ein- und ausblendet. Buttons zum Aktualisieren und Exportieren erscheinen, sobald du `onRefresh` und `onExport` übergibst.

```bash
npx wingo-ui@latest add kpi-dashboard
```

```tsx
"use client";

import { useState } from "react";
import { KpiDashboard, KPI_DASHBOARD_SAMPLE } from "@/components/ui/kpi-dashboard";
import type { DateRange } from "@/lib/date-utils";

export function SalesDashboard() {
  const [period, setPeriod] = useState<DateRange>({ from: new Date(2026, 8, 1), to: new Date(2026, 8, 30) });
  return (
    <KpiDashboard
      title="Dashboard"
      description="Northwind Software Inc. · Portland"
      data={KPI_DASHBOARD_SAMPLE}
      period={period}
      onPeriodChange={setPeriod}
      onRefresh={() => fetch("/api/dashboard")}
      widgetLinks={{ invoices: "/invoices", activity: "/activity" }}
      locale="en-US"
    />
  );
}
```

Der Block zeigt Daten an; sie für einen Zeitraum zu laden, ist Aufgabe deiner App. `onRefresh` darf ein Promise zurückgeben: Der Button dreht sich, bis es erledigt ist, und meldet dann die Uhrzeit des Updates. Jeder Eintrag in `data.kpis` ist ein `KpiItem` mit denselben Ideen wie Stat Card: `value`, `format`, `delta`, `deltaFormat` (inklusive `points` für Prozentpunkte), `invertTrend`, `sparkline`, `goal`, `info` und `href`. Im Beispiel steht Outstanding bei $31,650 mit einem Delta von +4.1% und `invertTrend`, also wird der Anstieg der offenen Forderungen rot.

> Live-Demo (KPI Dashboard): Wähl einen Zeitraum, leg den Vergleichsschalter um und sieh zu, wie die Deltas und die gestrichelte Reihe verschwinden. Mach das Fenster dann schmaler, um die KPI-Kacheln zu zweit pro Reihe zu sehen. Probier sie unter [KPI Dashboard](https://wingo-ui.com/components/kpi-dashboard) aus und installier sie mit `npx wingo-ui@latest add kpi-dashboard`.

## Wie klappt das KPI-Raster auf dem Smartphone zusammen?

Das Dashboard misst seine eigene Breite mit Container Queries, nicht den Viewport. Eine Sidebar kann es also nie in ein kaputtes Layout quetschen. Mit dem Standard `kpiColumns={0}` (automatisch):

| Breite des Dashboards | KPI-Kacheln pro Reihe | Widgets |
|---|---|---|
| unter 576px | 2, eine ungerade letzte Kachel streckt sich über die ganze Reihe | eine Spalte |
| 576px bis 671px | 3 (2 bei genau 4), übrige Kacheln strecken sich | eine Spalte |
| 672px bis 1023px | 3 (2 bei 4 Kacheln) | zwei Spalten |
| ab 1024px | alle Kacheln in einer Reihe, bis zu 6 (mehr brechen in Reihen um) | zwei Spalten, ab 1152px drei |

Das Widget mit den letzten Rechnungen wechselt von einer Tabelle zu Karten, sobald es schmaler als 672px ist. Auf dem Smartphone klappen auch die Aktionen im Header zusammen: Aktualisieren und Exportieren wandern in einen einzigen ⋯-Button, der ein Action Sheet öffnet, und die Zeitraumauswahl öffnet sich als Bottom Sheet statt als Popover. `StatGroup` allein nutzt Viewport-Breakpoints (zwei Spalten als Basis, vier ab `lg`), und in der Größe `md` schrumpfen die Werte, damit ein Währungsbetrag noch auf einen 360px breiten Screen passt. Zwei pro Reihe sind der richtige Standard auf dem Smartphone: Eine pro Reihe macht aus vier KPIs einen ganzen Screen zum Scrollen, und bei drei bleiben jeder Kachel auf einem 360px breiten Screen etwa 100px für eine Zahl wie `$128,450`.

## Was sind die typischen Fehler bei KPI Cards?

Die meisten Fehler lassen eine Karte präzise aussehen, während sie in die Irre führt:

- **Nach Vorzeichen färben.** Rot für jeden Rückgang lässt „Kosten um 8% gesunken“ wie ein Problem aussehen. Entscheide pro Kennzahl, ob weniger gut ist.
- **Verschiedene Zeiträume vergleichen.** „+12% ggü. Vormonat“ am 15. September vergleicht einen halben Monat mit einem ganzen. Vergleich mit denselben Tagen des Vorzeitraums, oder kennzeichne den angebrochenen Zeitraum.
- **Prozent und Punkte mischen.** Eine Conversion Rate, die von 20% auf 23% steigt, legt um 3 Punkte zu, oder um 15%. Entscheide dich für eins und sag dazu, welches.
- **0 zeigen, wenn es keine Daten gibt.** Bei `null` gehört ein Strich („–“) hin, nicht `$0`, denn das liest sich wie ein echter und sehr schlechter Monat.
- **Bei jedem Refresh hochzählen.** Animier einmal; danach wechselst du von der alten Zahl zur neuen, sonst verlieren die Leute das Vertrauen in die Zahlen.

Für die Chart-Seite eines Dashboards lies [React Charts mit Tailwind](https://wingo-ui.com/de/blog/react-charts-tailwind) und, für Sparklines in Tabellenzellen auf einer gemeinsamen Skala, [React Sparkline](https://wingo-ui.com/de/blog/react-sparkline), und für eine ganze Admin-App mit Tabellen und Einstellungen rund um diese Karten das [Tutorial zum Next.js Admin Dashboard](https://wingo-ui.com/de/blog/nextjs-admin-dashboard-tutorial). Wenn du noch eine Bibliothek für das ganze Dashboard suchst, lies [die beste React-Komponentenbibliothek für Dashboards](https://wingo-ui.com/de/blog/best-react-component-library-for-dashboard). Weitere Guides wie dieser stehen unter [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) ist der Pillar dieser Reihe.

## Was mache ich als Nächstes?

Öffne die [Doku zu Stat Card](https://wingo-ui.com/components/stat-card) und probier die Props im Playground aus; Doku, Props und Live-Demos kannst du ohne Konto nutzen. Stat Card, Trend Badge, Sparkline und das KPI Dashboard gehören zu Pro ($8 im Monat, $80 im Jahr oder einmalig $150, siehe [Preise](https://wingo-ui.com/de/pricing)), und ein kostenloses Konto gibt dir den Quellcode aller kostenlosen Items, wenn du mit den Grundlagen anfangen willst.

## Komponenten in diesem Artikel

- [Stat Card](https://wingo-ui.com/components/stat-card) (Pro): A React stat card for dashboards: a label, a big number that counts up, a delta pill that knows good from bad, a sparkline and a goal bar. Installation: `npx wingo-ui@latest add stat-card`
- [KPI Dashboard](https://wingo-ui.com/components/kpi-dashboard) (Pro): A React KPI dashboard: metric tiles with deltas, revenue against the last period, sources, funnel, top sellers, invoices and activity. Installation: `npx wingo-ui@latest add kpi-dashboard`
- [Trend badge](https://wingo-ui.com/components/trend-badge) (Pro): A React trend badge, the delta chip for KPIs, table cells and leaderboards: an arrow, a signed change and a color that says if it is good. Installation: `npx wingo-ui@latest add trend-badge`
- [Sparkline](https://wingo-ui.com/components/sparkline) (Pro): A React sparkline: a word-sized chart for table cells, list rows, KPI tiles and running text, as a line, an area, bars or win / loss ticks. Installation: `npx wingo-ui@latest add sparkline`

## Häufige Fragen

### Hat shadcn/ui eine KPI-Card-Komponente?

Nein. Stand November 2026 hat shadcn/ui keine KPI- oder Stat-Card-Komponente. Sein Block dashboard-01 enthält eine Datei SectionCards, die Card und Badge mit fest eingetragenen Zahlen kombiniert, und diese Datei passt du für deine eigenen Kennzahlen an.

### Wie zeige ich in einer React KPI Card einen Rückgang als gut an?

Trenn den Pfeil von der Farbe. Der Pfeil folgt dem Vorzeichen der Änderung, die Farbe ihrer Bedeutung: Bei Kosten, Churn und Antwortzeit ist ein Rückgang positiv. In Wingo UI ist das die Prop invertTrend an StatCard, TrendBadge und Sparkline.

### Wie viele KPI Cards sollte ein Dashboard zeigen?

Vier bis sechs in der obersten Reihe sind eine übliche Wahl, denn mehr Kacheln werden auf einem Laptop zu schmal zum Lesen und schieben die Charts unter den sichtbaren Bereich. Das KPI Dashboard setzt ab 1024px eigener Breite bis zu sechs Kacheln in eine Reihe und bricht mehr davon auf mehrere Reihen um.

### Wie sollten sich KPI Cards auf dem Smartphone verhalten?

Zwei Karten pro Reihe sind das übliche Layout auf dem Smartphone: Eine pro Reihe verschwendet Höhe, drei werden bei 360px für einen Währungsbetrag zu eng. Lass die letzte Kachel bei einer ungeraden Anzahl über die ganze Reihe laufen, verkleinere die Zahl, bis sie passt, und halte Delta und Label lesbar.

### Sollten KPI-Zahlen animiert sein?

Ein kurzes Count-up beim ersten Anzeigen hilft dem Auge, auf den Zahlen zu landen. Das Server-HTML und Screenreader sollten aber den Endwert bekommen, und bei reduzierter Bewegung sollte die Animation entfallen. Spätere Updates zählen von der Zahl auf dem Bildschirm aus, nicht von null.

---

Quelle: https://wingo-ui.com/de/blog/shadcn-kpi-cards
