# React Stepper: Zustände, Varianten und Smartphones

> Ein React Stepper für Checkout, Onboarding und KYC: Kreise, Balken oder Punkte, was jeder Schrittzustand bedeutet und wie er auf dem Handy kompakt wird.

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

## Kurz gesagt

Ein React Stepper zeigt, wo jemand in einer festen Abfolge steht: eine geordnete Liste, in der jeder Schritt erledigt, aktuell, ausstehend, fehlgeschlagen oder im Ladezustand ist, mit aria-current="step" auf dem aktuellen Schritt. Nimm nummerierte Kreise für Formulare, Balken für den Checkout, Punkte fürs Onboarding und eine vertikale Liste, wenn Schritte Beschreibungen brauchen. Unter etwa 640px sollte ein horizontaler Stepper zu einem Header mit „Step 2 of 4“ und Fortschrittsbalken zusammenklappen. Genau das macht die Steps-Komponente von Wingo UI per CSS.

Ein React Stepper beantwortet eine Frage auf einen Blick: Wie weit bin ich, und was fehlt noch? Checkouts, Onboarding-Flows, Identitätsprüfungen (KYC) und lange Einstellungsformulare nutzen alle einen. Schwierig sind drei Dinge: die Zustände (wie sieht ein fehlgeschlagener oder ladender Schritt aus?), das Layout (fünf Schritte mit Titeln passen nicht aufs Handy) und die Barrierefreiheit (eine Reihe Kreise sagt einem Screenreader ohne das richtige Markup nichts). Dieser Guide geht jeden Punkt mit der [Steps](https://wingo-ui.com/components/steps)-Komponente von Wingo UI durch, der Bibliothek, die wir bauen, und vergleicht sie mit den wichtigsten Alternativen. Sitzt der Stepper über einem Formular, behandelt das [Tutorial zum React Multi Step Form](https://wingo-ui.com/de/blog/react-multi-step-form) Validierung, gespeicherte Entwürfe und Übergänge.

## Wann solltest du einen Stepper verwenden?

Nimm einen, wenn die Aufgabe eine feste Reihenfolge hat, drei bis sieben Schritte und ein klares Ende. Jeder Schritt sollte vom vorherigen abhängen oder sich in dieser Reihenfolge zumindest besser lesen: Versand vor Zahlung, Ausweis vor Adressnachweis.

In zwei Fällen lässt du ihn weg. Sind die Abschnitte unabhängig und springen die Leute frei zwischen ihnen hin und her, nimm [Tabs](https://wingo-ui.com/components/tabs); ein Stepper suggeriert eine Reihenfolge, die es nicht gibt. Gibt es nur einen langen Schritt, reicht ein einfacher [Progress](https://wingo-ui.com/components/progress)-Balken.

## Welche Stepper-Variante passt zu welchem Flow?

Nummerierte Kreise passen zu Formularen, Balken zum Checkout und Punkte zum Onboarding. In Steps wählst du sie mit `variant`:

| Variante | Sieht aus wie | Gut für |
| --- | --- | --- |
| `circles` (Standard) | Nummerierte Marker, durch Linien verbunden, Titel darunter oder daneben | Formulare und Wizards, Konto-Einrichtung |
| `bars` | Ein Segment pro Schritt, der Titel darunter | Checkout Stepper, kurze Flows mit kurzen Titeln |
| `dots` | Kleine Punkte, der aktuelle breiter | Onboarding-Karussells, drei bis fünf Slides |

Zwei Layout-Props regeln die Anordnung. `orientation="vertical"` stapelt die Schritte in einer Spalte, mit Beschreibungen neben den Markern. Ein vertikaler Stepper passt zu KYC und Kontoeröffnung, wo jeder Schritt eine Zeile Erklärung braucht („Kontoauszug oder Nebenkostenabrechnung“), und er funktioniert bei jeder Breite. `labelPlacement="end"` setzt horizontale Titel neben die Marker statt darunter.

Dazu kommen die visuellen Props, die alle Komponenten von Wingo UI gemeinsam haben: `size` (`sm`, `md`, `lg`: Marker mit 24, 28 oder 32px), `tone` (standardmäßig neutral, sonst brand, success, warning, danger, info), `color` für jede CSS-Farbe und `connector="dashed"`, um die Verbindungslinien zu den noch ausstehenden Schritten gestrichelt zu zeichnen.

```bash
npx wingo-ui@latest add steps
```

> Live-Demo (Steps): Klick auf Continue: Die Verbindungslinie füllt sich bis zum nächsten Schritt, der Marker ploppt auf und das Häkchen zeichnet sich ein. Klick dann auf einen erledigten Schritt, um zu ihm zurückzugehen. Auf dem Handy zeigt derselbe Stepper den kompakten Header mit Step 2 of 4. Probier sie unter [Steps](https://wingo-ui.com/components/steps) aus und installier sie mit `npx wingo-ui@latest add steps`.

## Was bedeutet jeder Schrittzustand?

Jeder Schritt hat einen von fünf Zuständen. Drei leitet Steps aus dem aktuellen `value` ab: Schritte davor sind erledigt, der Schritt bei `value` ist aktuell, die danach stehen aus. Die anderen zwei sind immer explizit und werden mit `status` am Schritt gesetzt:

| Zustand | Marker | Screenreader sagt | Gesetzt durch |
| --- | --- | --- | --- |
| `complete` | Ein Häkchen, das sich selbst einzeichnet | „Completed“ | Position vor `value` oder `status` |
| `current` | In der `tone`-Farbe gefüllt, mit weichem Ring | „Current step“ plus `aria-current="step"` | Position bei `value` |
| `upcoming` | Die Nummer (oder `icon`) auf leichter Tönung | Nichts weiter | Position nach `value` |
| `error` | Ein rotes „!“ | „Needs attention“ | `status: "error"` |
| `loading` | Ein Spinner | „In progress“ | `status: "loading"` |

Fehler und Laden sind explizit, weil nur dein Code sie kennt. Ein KYC-Flow ist das klarste Beispiel: Die Identitätsprüfung läuft auf einem Server, kann Sekunden dauern und kann aus einem Grund scheitern, den die Person selbst beheben kann.

```tsx
"use client";

import { useState } from "react";
import { Steps, type StepItem } from "@/components/ui/steps";
import { Button } from "@/components/ui/button";

type Check = "idle" | "checking" | "failed" | "passed";

export function IdentityVerification({ verify }: { verify: () => Promise<boolean> }) {
  const [check, setCheck] = useState<Check>("idle");

  const steps: StepItem[] = [
    { id: "personal", title: "Persönliche Daten", description: "Emma Carter" },
    {
      id: "identity",
      title: "Identitätsprüfung",
      description:
        check === "failed" ? "Das Foto ist unscharf. Nimm es noch einmal auf." : check === "checking" ? "Dein Ausweis wird geprüft" : "Führerschein oder Reisepass",
      status: check === "checking" ? "loading" : check === "failed" ? "error" : undefined,
    },
    { id: "address", title: "Adressnachweis", description: "Kontoauszug oder Nebenkostenabrechnung" },
    { id: "done", title: "Fertig" },
  ];

  const send = async () => {
    setCheck("checking");
    setCheck((await verify().catch(() => false)) ? "passed" : "failed");
  };

  return (
    <div className="flex flex-col gap-5">
      <Steps steps={steps} value={check === "passed" ? "address" : "identity"} orientation="vertical" clickable="none" />
      {check !== "passed" && (
        <Button loading={check === "checking"} loadingText="Wird geprüft" onClick={send}>
          {check === "failed" ? "Foto erneut hochladen" : "Foto senden"}
        </Button>
      )}
    </div>
  );
}
```

Schreib den Grund für einen Fehler in die `description` des Schritts, wie oben. Ein rotes „!“ sagt den Leuten, dass etwas nicht stimmt; der Text sagt ihnen, was sie tun sollen. `optional: true` zeigt einen Hinweis „Optional“ unter dem Titel (bei Punkten, die keinen sichtbaren Titel haben, nur für Screenreader), und `disabled: true` sorgt dafür, dass ein Schritt nie klickbar wird.

## Welche Schritte sollten klickbar sein?

`clickable` entscheidet, welche Schritte Buttons sind. Der Standard `"completed"` macht erledigte Schritte, den aktuellen und fehlerhafte klickbar. Das deckt den häufigen Fall „zurück und die Adresse korrigieren“ ab, ohne dass jemand nach vorn springen kann. `"all"` macht jeden aktivierten Schritt zum Button, für Flows, in denen die Reihenfolge nur ein Vorschlag ist. `"none"` macht den Stepper zur reinen Anzeige, wie im KYC-Beispiel, wo nur der Server dich weiterbringt.

Klicks rufen `onValueChange(id, step)` auf. Ein Checkout Stepper verteilt sich meist auf mehrere Routen, also ist die URL maßgeblich: Gib jedem Schritt ein `href` und übergib die Link-Komponente deines Routers. Steps rendert klickbare Schritte als Links, und der aktuelle bekommt `aria-current="step"`:

```tsx
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { Steps, type StepItem } from "@/components/ui/steps";

const CHECKOUT: StepItem[] = [
  { id: "cart", title: "Warenkorb", href: "/checkout/cart" },
  { id: "shipping", title: "Versand", href: "/checkout/shipping" },
  { id: "payment", title: "Zahlung", href: "/checkout/payment" },
  { id: "review", title: "Prüfen", href: "/checkout/review" },
];

export function CheckoutProgress() {
  const pathname = usePathname();
  const current = CHECKOUT.find((step) => step.href === pathname)?.id ?? "cart";
  return <Steps steps={CHECKOUT} value={current} variant="bars" linkComponent={Link} />;
}
```

Mit dem Standardwert von `clickable` bleiben die ausstehenden Schritte reiner Text, also landet niemand mit leerem Warenkorb auf der Zahlungsseite. Sichere die Routen trotzdem auch auf dem Server ab; ein Stepper ist keine Zugriffskontrolle.

Ein Stolperstein: Der Vergleich von `usePathname()` mit `href` geht schief, sobald der Pfad ein Locale-Präfix oder einen abschließenden Slash enthält. Rendert der Stepper aus `app/checkout/layout.tsx`, liefert `useSelectedLayoutSegment()` aus `next/navigation` direkt `"shipping"`, und du kannst stattdessen mit der `id` des Schritts vergleichen.

## Wie passt ein Stepper aufs Handy?

Unter 640px wird ein horizontaler Stepper mit Kreisen oder Balken zu einem kompakten Header: „Step 2 of 4“ in kleiner Schrift, der aktuelle Titel, „Next: Payment“ rechts und ein dünner Fortschrittsbalken darunter. Beide Layouts stehen im HTML, und ein CSS-Breakpoint wählt eins aus. So ist schon das Server-Rendering auf dem Handy richtig, und nach der Hydration verschiebt sich nichts. `mobileVariant="same"` behält den vollen Stepper auf Handys, und `compact` zeigt den kompakten Header bei jeder Breite, etwa für eine schmale Card oder ein Sheet.

Vertikale Stepper und Punkte behalten ihr Layout bei jeder Größe, denn beide passen schon auf einen schmalen Screen. Ist eine horizontale Liste breiter als ihr Container und hast du den kompakten Header abgeschaltet, scrollt sie seitwärts und hält den aktuellen Schritt sichtbar.

Auf Touchscreens bekommen klickbare Marker und Punkte eine Trefferfläche von 44px, das Minimum, das wir für jedes Control nutzen. Die Begründung steht in [unserem Beitrag zur Größe von Touch Targets](https://wingo-ui.com/de/blog/minimum-touch-target-size-react-tailwind).

## Wie machst du einen Stepper barrierefrei?

Nutze eine geordnete Liste, markier den aktuellen Schritt mit `aria-current="step"`, schreib den Zustand jedes Schritts in Worten aus und unterstütze die Pfeiltasten. In Steps sieht das Markup so aus:

- **Eine geordnete Liste.** Steps rendert ein `<ol>` mit dem Namen „Progress“ (`labels.progress`), also sagt ein Screenreader eine Liste mit vier Einträgen und die Position jedes Eintrags an.
- **`aria-current="step"`** auf dem aktuellen Schritt, der Attributwert, den die ARIA-Spezifikation genau für diesen Fall definiert.
- **Zustand in Worten.** Der zugängliche Name jedes Schritts enthält seinen Zustand („Shipping, Completed“), denn Farbe und ein Häkchen-Icon sind für einen Screenreader unsichtbar.
- **Tastatur.** Tab erreicht jeden klickbaren Schritt; die Pfeiltasten links und rechts (bei vertikaler Ausrichtung hoch und runter) wechseln zwischen ihnen, Pos1 und Ende springen an die Enden.
- **Der kompakte Header** ist eine `progressbar` mit `aria-valuenow` und „Step 2 of 4“ als Textwert.

Alle diese Texte stecken in `labels`, eine Übersetzung oder ein anderer Tonfall braucht also nur ein Prop.

## Was ist mit einem kompletten Checkout Stepper in React?

Brauchst du einen kompletten Checkout statt nur der Anzeige, setzt der Block [Checkout Steps](https://wingo-ui.com/components/checkout-steps) vier Schritte (Lieferdaten, Versand, Zahlung und Prüfen) neben eine Sticky-Bestellübersicht. Er validiert jeden Schritt, zeigt Paketstationen und Abholpunkte, rechnet Zahlungsgebühren in die Summe ein und macht auf dem Handy aus jedem Schritt eine Seite in voller Höhe, mit Summe und Continue-Button über dem Home-Indikator. Sein Header nutzt den Stepper aus [Form Wizard](https://wingo-ui.com/components/form-wizard), `"horizontal"` oder `"progress"`.

Achte auf seine Standardwerte: Er wurde für den rumänischen Markt gebaut, also ist `country` auf `"RO"` gesetzt (Prüfung von Postleitzahl und Unternehmens-Steuernummer), `currency` auf `"RON"`, und der Company-Schalter fragt nach einer CUI. Setz für andere Märkte `country`, `currency` und `invoice={false}`.

> Live-Demo (Checkout steps): Wähl eine Versandart und drück Continue: Der Stepper markiert den Schritt als erledigt und die Summe in der Übersicht aktualisiert sich. Auf einem schmalen Screen klappt die Übersicht zu einer Leiste oben zusammen. Probier sie unter [Checkout steps](https://wingo-ui.com/components/checkout-steps) aus und installier sie mit `npx wingo-ui@latest add checkout-steps`.

## Wie schneidet Steps im Vergleich zu MUI und shadcn ab?

MUI liefert einen ausgereiften Stepper in Material UI, shadcn/ui hat keinen, und Wingo UI Steps ist der mit eingebautem Handy-Header sowie Fehler- und Ladezuständen. Die Details, Stand Oktober 2026 (Doku von Material UI v9.5):

| | Wingo UI Steps | MUI Stepper | shadcn/ui |
| --- | --- | --- | --- |
| Installation | `npx wingo-ui@latest add steps` | Paket `@mui/material` | Kein offizieller Stepper; Community-Registries wie ReUI |
| Optik | circles, bars, dots | Horizontale und vertikale Stepper, dazu ein separater MobileStepper (Text, Punkte, Fortschritt) | Hängt von der Registry ab |
| Zustände | complete, current, upcoming, error, loading | Active, completed, optional und ein Fehler-Beispiel | ReUI: active, completed, inactive, loading |
| Handy-Layout | Kompakter Header unter 640px, automatisch | Vertikaler Stepper oder MobileStepper, von dir gewählt | Liegt bei dir |
| Styling | Tailwind v4 Tokens, Quellcode in deinem Repo | Das Styling-System von MUI | Tailwind, Quellcode in deinem Repo |

Quellen: [MUI Stepper Doku](https://mui.com/material-ui/react-stepper/), [Komponentenliste von shadcn/ui](https://ui.shadcn.com/docs/components), [ReUI Stepper Doku](https://reui.io/docs/stepper).

MUI ist die bessere Wahl, wenn deine App schon Material UI nutzt: Der Stepper fügt sich in das übrige Design System ein, und laut der [MUI-Doku](https://mui.com/material-ui/react-stepper/) sind vertikale Stepper für schmale Bildschirme gedacht. Willst du einen shadcn Stepper, der sich mit der shadcn CLI installieren lässt, passt die komponierbare API von ReUI (`Stepper`, `StepperItem`, `StepperIndicator`) zu diesem Stil. Wingo UI Steps passt, wenn ein Tailwind Stepper die Zustände, den Handy-Header und die Tastaturbedienung schon fertig mitbringen soll.

## Wo fängst du am besten an?

Fang mit der [Steps-Doku](https://wingo-ui.com/components/steps) an: Playground und Beispiele für vertikale Schritte mit Icons, einen Flow mit Laden und Fehler, Balken, Punkte, verlinkte Schritte und den Handy-Header. Steps, Checkout Steps und Form Wizard gehören zu Wingo UI Pro: $8 im Monat, $80 im Jahr oder $150 einmalig, Stand Oktober 2026 ([Preise](https://wingo-ui.com/de/pricing)). Weitere Guides wie dieser stehen in der [Kategorie Komponenten-Guides](https://wingo-ui.com/de/blog/category/components), angefangen mit dem [Guide zu React-Formularkomponenten](https://wingo-ui.com/de/blog/react-form-components-guide).

## Komponenten in diesem Artikel

- [Steps](https://wingo-ui.com/components/steps) (Pro): A React stepper for checkouts, onboarding and KYC: circles, bars or dots, with complete, error and loading states and a phone header. Installation: `npx wingo-ui@latest add steps`
- [Checkout steps](https://wingo-ui.com/components/checkout-steps) (Pro): A React multi-step checkout: address and invoice, delivery with lockers, payment and a review that places the order, beside a summary. Installation: `npx wingo-ui@latest add checkout-steps`

## Häufige Fragen

### Was ist eine Stepper-Komponente in React?

Eine Fortschrittsanzeige für eine Aufgabe, die in geordnete Schritte aufgeteilt ist, etwa ein Checkout oder eine Registrierung. Sie zeigt, welche Schritte erledigt sind, welcher gerade dran ist und was noch fehlt, und sie kann den Sprung zurück zu einem erledigten Schritt erlauben.

### Hat shadcn/ui eine Stepper-Komponente?

Nein. Stand Oktober 2026 hat die offizielle Komponentenliste von shadcn/ui keinen Stepper. Community-Registries wie ReUI veröffentlichen einen, der sich mit der shadcn CLI installieren lässt, und du kannst auch selbst einen aus einer geordneten Liste und Tailwind-Klassen bauen.

### Wie mache ich einen React Stepper vertikal?

Ordne die Schritte in einer Spalte an, die Marker auf einer Seite, Titel und Beschreibungen daneben, und verbinde die Marker mit einer senkrechten Linie. In Wingo UI Steps ist das orientation="vertical", und das funktioniert bei jeder Bildschirmbreite.

### Wie sollte ein Stepper auf dem Handy aussehen?

Eine Reihe nummerierter Kreise mit Titeln passt selten auf einen 360px breiten Bildschirm. Zeig stattdessen einen kompakten Header mit Schrittzahl, aktuellem Titel, nächstem Schritt und Fortschrittsbalken, oder wechsle zu einer vertikalen Liste, wenn die Leute jeden Schritt sehen müssen.

### Sollten erledigte Schritte in einem Stepper klickbar sein?

Meistens ja: Zu einem erledigten Schritt zurückzugehen, um etwas zu korrigieren, ist der häufigste Grund, auf einen Stepper zu klicken. Der Sprung nach vorn über nie ausgefüllte Schritte sollte gesperrt bleiben, außer die Schritte sind wirklich unabhängig.

---

Quelle: https://wingo-ui.com/de/blog/react-stepper-component
