Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelog
    1. Startseite
    2. Blog
    3. Next.js und Tailwind CSS
    4. Next.js Component Library im App Router einrichten
    Read in English
    1. Blog
    2. Next.js und Tailwind CSS
    3. Next.js Component Library im App Router einrichten
    Next.js und Tailwind CSS
    Next.js und Tailwind CSS

    Next.js Component Library im App Router einrichten

    SR
    Serban Rusu · Gründer von Wingo UI
    13. Okt. 2026 · 8 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Was macht eine Komponentenbibliothek fit für den App Router?
      1. "use client" genau in der Datei, die es braucht
      2. Kein window auf Modulebene
      3. Ein Theme ohne Flackern
      4. Tokens in CSS, nicht in einer JavaScript-Runtime
    2. Wie richte ich eine Next.js Component Library Schritt für Schritt ein?
      1. 1. App anlegen
      2. 2. Den dunklen Media-Block des Starters entfernen
      3. 3. init ausführen
      4. 4. Komponenten hinzufügen
      5. 5. Das Root-Layout mit den Providern umschließen
      6. 6. Eine Client-Komponente in einer Server-Seite nutzen
      7. 7. Einen Theme Toggle ergänzen
      8. 8. Für Pro-Komponenten anmelden
      9. 9. Komponenten aktuell halten
    3. Was prüfe ich, wenn etwas falsch aussieht?
    4. Wie geht es weiter?
    5. Häufige Fragen
      1. Kann ich eine Client-Komponentenbibliothek in Next.js Server Components nutzen?
      2. Warum braucht das Root-Layout suppressHydrationWarning?
      3. Warum wechselt mein Theme Toggle nach wingo-ui init die Farben nicht?
      4. Brauchen die kostenlosen Komponenten von Wingo UI einen Account oder API-Key?
      5. Funktioniert dieses Setup mit Next.js 15?

    Kurz gesagt

    Eine Komponentenbibliothek passt zum Next.js App Router, wenn jede interaktive Datei mit use client beginnt, beim Laden des Moduls nichts auf window zugreift, die Farben als CSS-Variablen in globals.css liegen und das Theme vor dem ersten Paint gesetzt wird. In einer neuen Next.js-16-App entfernst du den prefers-color-scheme-Block des Starters, führst npx wingo-ui@latest init aus, fügst Komponenten hinzu und umschließt das Root-Layout mit next-themes und UIProvider, mit suppressHydrationWarning am html-Tag. Server-Seiten importieren die Komponenten direkt; Event-Handler wandern in kleine Client-Dateien.

    Veröffentlicht am 13. Okt. 2026

    Die meisten Anleitungen für eine Next.js Component Library hören beim Installationsbefehl auf. Die Fragen kommen aber direkt danach: Welche Dateien brauchen "use client"? Warum kann eine Server-Seite kein onClick an einen Button geben? Warum flackert das dunkle Theme beim Neuladen? Und warum tut ein Theme Toggle in einer frischen App gar nichts? Dieser Guide beantwortet zuerst diese Fragen. Danach geht er ein komplettes Next.js Component Library Setup mit echten Befehlen durch, von create-next-app bis zum Update der Komponenten Monate später.

    Alles hier haben wir am 13. Oktober 2026 ausgeführt, mit create-next-app@latest (Next.js 16.4.0, React 19.3.0, Tailwind CSS v4), der wingo-ui CLI 1.0.3 und next-themes 0.4.6. Die Bibliothek ist unsere eigene, Wingo UI, aber Teil 1 gilt für jede Bibliothek, deren Quellcode dir gehört, auch für ein shadcn Next.js App Router Projekt. Wie die Tokens im Detail funktionieren, erklärt der Pillar-Artikel zu Tailwind v4 Design Tokens.

    Was macht eine Komponentenbibliothek fit für den App Router?

    Vier Eigenschaften. Hat eine Bibliothek sie, steht dir der App Router nicht im Weg. Fehlen sie, schreibst du am Ende Wrapper.

    "use client" genau in der Datei, die es braucht

    Im App Router ist jede Datei eine Server Component, bis sie etwas anderes sagt. Eine Bibliothek aus use client Komponenten markiert jede interaktive Datei ganz oben. So liegt die Grenze in der Bibliothek, und deine Seiten bleiben Server Components. Jede Datei von Wingo UI, die State, Effects oder Context nutzt, beginnt mit der Direktive, darunter Button, Card, Dialog und der UIProvider in lib/ui-config.tsx.

    Daraus ergibt sich eine Regel, die du dir merken solltest: Eine Server-Seite kann diese Komponenten rendern und ihnen Strings, Zahlen, Objekte und JSX übergeben, aber keine Funktionen. <Button onClick={...}> in einer Server-Seite schlägt fehl, weil React keine Funktion vom Server an den Browser schicken kann. Verschieb den Handler in eine kleine Client-Datei. Schritt 6 zeigt das Muster.

    Kein window auf Modulebene

    Beim Server-Rendering wird jedes Modul auf dem Server importiert, und dort gibt es weder window noch document noch matchMedia. Eine Bibliothek, die diese Objekte beim Laden des Moduls oder während des Renderns liest, stürzt ab oder rendert auf beiden Seiten etwas anderes. Unsere hält sich an eine Regel: kein window und kein document auf Modulebene oder während des Renderns. Browser-Werte werden in Effects oder in useSyncExternalStore mit einem Server-Fallback gelesen. Deshalb gibt useIsMobile() auf dem Server false zurück und aktualisiert sich nach der Hydration. Der Guide zum React Use Mobile Hook zeigt, warum das fürs Layout wichtig ist.

    Ein Theme ohne Flackern

    Der Server weiß nicht, ob jemand Dark Mode gewählt hat, denn diese Wahl liegt in localStorage. Die Lösung ist ein winziges Script, das die Klasse auf <html> vor dem ersten Paint setzt. next-themes fügt dieses Script für dich ein. React sieht dann ein <html>-Element, das vom Server-HTML abweicht, und deshalb trägt das Root-Layout suppressHydrationWarning. Mehr dazu in Schritt 5 und in unseren Guides zu Next.js und Tailwind CSS.

    Tokens in CSS, nicht in einer JavaScript-Runtime

    Farben, Radien, Schatten und Animationszeiten sind CSS-Variablen in globals.css, die über @theme inline auf Utilities abgebildet werden. Dark Mode tauscht die Variablen unter .dark. Kein JavaScript muss laufen, damit klar ist, was bg-surface bedeutet. Server Components rendern also die richtigen Farben, und es gibt keinen Theme Provider, auf den du warten musst. Deshalb lassen sich Next.js Tailwind v4 Komponenten so leicht themen: Du bearbeitest eine einzige Datei.

    Wie richte ich eine Next.js Component Library Schritt für Schritt ein?

    1. App anlegen

    Überspring das in einem bestehenden Projekt, das schon mit Tailwind CSS v4 läuft.

    bash
    npx create-next-app@latest my-app --ts --tailwind --eslint --app --import-alias "@/*"
    cd my-app

    Mit 16.4.0 legt der Befehl eine app/globals.css mit @import "tailwindcss";, eine tsconfig.json mit dem Alias @/* und eine dunkle Palette in @media (prefers-color-scheme: dark) an.

    2. Den dunklen Media-Block des Starters entfernen

    Diesen Schritt übersieht man leicht. Findet wingo-ui init einen prefers-color-scheme-Block, respektiert es ihn und legt die dunklen Werte der Bibliothek ebenfalls dort ab. Das passt für eine App, die nur der Systemeinstellung folgt. next-themes schaltet aber eine .dark-Klasse um, und eine Media Query ignoriert diese Klasse. Lösch diesen Block aus app/globals.css, bevor du init ausführst:

    css
    @media (prefers-color-scheme: dark) {
    :root {
    --background: #0a0a0a;
    --foreground: #ededed;
    }
    }

    Ohne den Block schreibt init stattdessen einen .dark-Block und @custom-variant dark (&:is(.dark *));. Wir haben init in beiden Varianten ausgeführt: Mit dem Block meldete es dark mode: media, ohne ihn dark mode: class. Die Theming-Doku beschreibt beide Modi.

    3. init ausführen

    bash
    npx wingo-ui@latest init

    Die CLI erkennt das Framework anhand der package.json, den Alias @/* anhand der tsconfig.json und das Stylesheet, das Tailwind importiert. Dann:

    • installiert sie clsx und tailwind-merge und legt lib/utils.ts mit dem Helper cn an,
    • führt sie die Design Tokens in app/globals.css zusammen und ergänzt nur Namen, die du noch nicht hast, sodass --background und --foreground aus dem Starter bleiben,
    • schreibt sie wingo-ui.json mit Framework, Aliassen, Stylesheet und Paketmanager.

    Unser Durchlauf gab added 72 variables, 46 dark values, 72 @theme mappings, @custom-variant dark, base border color (dark mode: class) aus. Mit --yes überspringt sie die Abfrage, ob du einen Coding-Agenten verbinden willst.

    4. Komponenten hinzufügen

    bash
    npx wingo-ui@latest add button dialog card

    Die Dateien landen in components/ui, hooks und lib. Der Befehl holt alles, was die drei Items importieren: den Drawer, zu dem Dialog auf Smartphones wird, lib/motion.ts, lib/tones.ts, lib/ui-config.tsx und vier Hooks. Außerdem installiert er die npm-Pakete (@radix-ui/react-dialog, motion, vaul, lucide-react und ein paar weitere). Kostenlose Items brauchen weder Account noch Key.

    wingo-ui.json speichert jetzt jedes Item mit seiner Version und einem SHA-256-Hash pro Datei, und die CLI legt die installierten Kopien in .wingo-ui/ ab. Committe beides: Damit kann update neue Releases in Dateien mergen, die du bearbeitet hast.

    5. Das Root-Layout mit den Providern umschließen

    Installier next-themes und ersetz dann app/layout.tsx:

    bash
    npm install next-themes
    tsx
    // app/layout.tsx
    import { ThemeProvider } from "next-themes"
    import { UIProvider } from "@/lib/ui-config"
    import "./globals.css"
    export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
    <html lang="en" suppressHydrationWarning>
    <body>
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
    <UIProvider locale="en-US" defaults={{ button: { radius: "full" } }}>
    {children}
    </UIProvider>
    </ThemeProvider>
    </body>
    </html>
    )
    }

    Das Layout bleibt eine Server Component. ThemeProvider und UIProvider sind Client Components, und die Props, die sie bekommen, sind reine Daten. Das ist also erlaubt.

    • attribute="class" sorgt dafür, dass next-themes class="dark" auf <html> setzt. Danach richten sich die .dark-Tokens und die dark:-Variante.
    • suppressHydrationWarning ist nötig, weil das Theme-Script <html> ändert, bevor React hydriert. Es gilt nur für die Attribute dieses einen Elements, eine Ebene tief, und versteckt daher keine echten Mismatches in deinen Seiten.
    • disableTransitionOnChange verhindert, dass alle Farbübergänge gleichzeitig animieren, wenn das Theme wechselt.
    • UIProvider setzt app-weite Defaults pro Komponentenname und die Locale für Datums- und Zahlenformate. Hier ist jeder Button voll abgerundet, solange ein Button radius nicht selbst setzt; explizite Props gewinnen immer.

    6. Eine Client-Komponente in einer Server-Seite nutzen

    Seiten bleiben asynchrone Server Components, die Daten laden. Komponenten ohne Handler renderst du direkt von der Seite aus, und JSX darf durch Props wandern. Ein ganzer Dialog mit Trigger und Footer funktioniert also ohne eigene Client-Datei:

    tsx
    // app/page.tsx
    import { Button } from "@/components/ui/button"
    import { Dialog, DialogClose } from "@/components/ui/dialog"
    import { InviteForm } from "./invite-form"
    async function getProject() {
    return { name: "Website-Relaunch", members: 4 }
    }
    export default async function Page() {
    const project = await getProject()
    return (
    <main className="mx-auto flex max-w-xl flex-col gap-6 p-6">
    <h1 className="text-xl font-semibold">{project.name}</h1>
    <Dialog
    trigger={<Button tone="brand">Leute einladen</Button>}
    title="Leute einladen"
    description={`Sie bekommen Zugriff auf ${project.name}.`}
    footer={
    <DialogClose asChild>
    <Button variant="soft">Fertig</Button>
    </DialogClose>
    }
    >
    <InviteForm />
    </Dialog>
    </main>
    )
    }

    Der Teil mit State und onClick kommt in eine eigene Datei:

    tsx
    // app/invite-form.tsx
    "use client"
    import { useState } from "react"
    import { Button } from "@/components/ui/button"
    export function InviteForm() {
    const [sent, setSent] = useState(false)
    return (
    <Button variant="outline" onClick={() => setSent(true)} disabled={sent}>
    {sent ? "Einladung gesendet" : "Einladung an emma@example.com senden"}
    </Button>
    )
    }

    Beide Dateien bestehen tsc --noEmit und ESLint mit der Konfiguration, die create-next-app erzeugt. Der Dialog unten ist dieselbe Komponente mit einem Formular darin. Probier ihn auch auf einem schmalen Bildschirm aus.

    Tippe auf Edit, um den Dialog zu öffnen. Unter 768px öffnet sich dieselbe Komponente als Bottom Sheet, das du zum Schließen nach unten ziehst
    $ npx wingo-ui@latest add dialog
    FreeDoku: Dialog

    7. Einen Theme Toggle ergänzen

    Theme Toggle ist eine Pro-Komponente: ein animierter Button mit Sonne und Mond, ein Segmented Control oder ein Dropdown, alle auf Basis von next-themes. Im kostenlosen Tarif reicht eine kurze Client-Datei:

    tsx
    // components/theme-switch.tsx
    "use client"
    import { Moon, Sun } from "lucide-react"
    import { useTheme } from "next-themes"
    import { Button } from "@/components/ui/button"
    export function ThemeSwitch() {
    const { resolvedTheme, setTheme } = useTheme()
    return (
    <Button
    variant="ghost"
    size="icon"
    aria-label="Theme wechseln"
    onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
    >
    <Moon className="dark:hidden" />
    <Sun className="hidden dark:block" />
    </Button>
    )
    }

    Die Icons wechseln per CSS. Das Server-HTML und der erste Client-Render stimmen also überein, und du brauchst kein mounted-Flag. Die häufigsten Ursachen für die Hydration-Warnung behandelt unser Fix für den next-themes Hydration Error, die Variante und die Tokens hinter dem Toggle unser Guide zu Tailwind v4 Dark Mode. Weitere Artikel findest du unter Next.js und Tailwind CSS.

    8. Für Pro-Komponenten anmelden

    Pro-Items brauchen einen Key. Melde die CLI einmal pro Rechner an:

    bash
    npx wingo-ui@latest login

    Sie öffnet den Browser, um das Gerät freizugeben, und speichert einen Key unter ~/.config/wingo-ui. Auf einem Server oder in der CI übergibst du stattdessen einen Key aus deinem Account:

    bash
    npx wingo-ui@latest login --key wui_...
    # oder
    export WINGO_UI_API_KEY=wui_...

    Ohne Key bricht das Hinzufügen eines Pro-Items mit einer Meldung ab, die das Item nennt und auf die Tarife verlinkt. Die Tarife stehen auf der Preisseite.

    9. Komponenten aktuell halten

    bash
    npx wingo-ui@latest outdated # was sich upstream geändert hat
    npx wingo-ui@latest diff button # deine Datei gegen das neueste Release
    npx wingo-ui@latest update # neue Releases in deine Kopien mergen

    Wir haben ein Label in einer installierten Datei geändert und diff ausgeführt: Es gab einen Unified Diff unserer Änderung gegen upstream aus. update macht einen Three-Way-Merge mit der Kopie in .wingo-ui/, behält deine Änderungen und markiert echte Konflikte wie git. Die CLI-Doku listet jedes Flag auf.

    Was prüfe ich, wenn etwas falsch aussieht?

    SymptomWahrscheinliche UrsacheLösung
    Theme Toggle ändert nichtsDunkle Werte stehen in einem prefers-color-scheme-Media-BlockSchritt 2, dann init erneut ausführen
    „Functions cannot be passed directly to Client Components“onClick wird von einer Server-Seite übergebenHandler in eine Client-Datei verschieben (Schritt 6)
    Hydration-Warnung auf <html>suppressHydrationWarning fehltNur auf <html> ergänzen
    Komponenten ohne Styles, bg-surface wirkt nichtTokens fehlen im Stylesheet, das Tailwind liestnpx wingo-ui@latest init erneut ausführen; es ergänzt nur fehlende Tokens
    Pro-Item lässt sich nicht installierenKein Key auf diesem Rechnernpx wingo-ui@latest login oder WINGO_UI_API_KEY

    Wie geht es weiter?

    Fang mit den kostenlosen Basics an: npx wingo-ui@latest add button dialog card. Danach folgst du der Installations-Doku für die shadcn CLI und den manuellen Weg. Wenn du UI mit Claude Code, Codex oder Cursor schreibst, verbinde den MCP-Server, damit der Agent die Bibliothek durchsucht, bevor er eine Komponente schreibt. Du baust mit Vite statt mit Next.js? Das shadcn Vite Setup zeigt dieselben Schritte dort.

    Komponenten in diesem Artikel

    • Button

      The React button component every screen starts with: five variants, six tones, all sizes, and a loading state that never jumps.

      Free
    • Dialog

      A React modal dialog for focused tasks: a spring-scaled card on desktop and a bottom sheet on phones, with nesting and scrolling.

      Free
    • UIProvider

      A React config provider for Wingo UI: app-wide default props for every component, the Intl locale and a reduced-motion policy.

      Free
    • Theme Toggle

      A React theme toggle for light, dark and system mode on next-themes: an animated sun and moon button, a segmented control or a menu.

      Pro

    Häufige Fragen

    Kann ich eine Client-Komponentenbibliothek in Next.js Server Components nutzen?

    Ja. Eine Server-Seite kann eine Datei mit use client importieren, rendern und ihr Strings, Zahlen und JSX übergeben. Funktionen wie onClick kann sie nicht übergeben, also steckst du Handler in eine kleine Client-Komponente und renderst diese in der Seite.

    Warum braucht das Root-Layout suppressHydrationWarning?

    Bevor React hydriert, gibt ein Script von next-themes dem html-Element die Klasse dark oder light. Das Server-HTML hatte diese Klasse nicht, also würde React einen Mismatch melden. Das Attribut unterdrückt die Warnung nur für dieses eine Element.

    Warum wechselt mein Theme Toggle nach wingo-ui init die Farben nicht?

    Das Stylesheet von create-next-app bringt einen Block @media (prefers-color-scheme: dark) mit, und init legt die dunklen Werte dort ab, wenn es einen findet. Damit die Klasse von next-themes gewinnt, löschst du den Block vor init oder verschiebst die dunklen Werte in einen .dark-Block und ergänzt @custom-variant dark (&:is(.dark *));

    Brauchen die kostenlosen Komponenten von Wingo UI einen Account oder API-Key?

    Nein. Kostenlose Items wie button, card und dialog installierst du mit npx wingo-ui@latest add, ganz ohne Key. Pro-Items brauchen einmal pro Rechner npx wingo-ui@latest login oder WINGO_UI_API_KEY in der CI.

    Funktioniert dieses Setup mit Next.js 15?

    Wir haben jeden Schritt auf Next.js 16.4.0 ausgeführt. Die Bibliothek braucht React 19 und Tailwind CSS v4, beides geht auch in einem Next.js-15-Projekt mit App Router. Dort haben wir die Schritte aber nicht wiederholt.

    • Next.js
    • App Router
    • Setup
    • Installation
    • Tailwind CSS v4

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Next.js und Tailwind CSS

    shadcn Vite Setup mit Tailwind CSS v4 und React 19

    shadcn Vite Setup, getestet mit Vite 8 und TypeScript 6: Tailwind-v4-Plugin, @-Alias in tsconfig.app.json, Dark Mode ohne Next.js, dann Komponenten hinzufügen.

    SRSerban Rusu·13. Okt. 2026·7 Min. Lesezeit
    UI mit KI-Agenten bauen

    AGENTS.md vs CLAUDE.md vs Cursor-Regeln für React

    AGENTS.md vs CLAUDE.md vs Cursor-Regeln für React und Tailwind: wer welche Datei liest (Oktober 2026) und eine Regeldatei, die Agenten bei deinen Tokens hält.

    SRSerban Rusu·9. Okt. 2026·14 Min. Lesezeit
    Komponenten-Guides

    shadcn Komponenten updaten, ohne Änderungen zu verlieren

    shadcn Komponenten updaten, ohne Änderungen zu verlieren: was shadcn diff und add --diff zeigen, was ein 2-Wege-Diff verschweigt und wie der 3-Wege-Merge geht.

    SRSerban Rusu·9. Okt. 2026·10 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Guides, Tutorials und Vergleiche aus dem Wingo UI Blog, sobald sie erscheinen. Die meisten Artikel sind auf Englisch.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Theme-Generator

    Ressourcen

    • Doku
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI