Design wechseln

shadcn/ui Installation und Theme-Anpassung: Der vollständige Leitfaden (inkl. CSS-Variablen)

Beim ersten Kontakt mit shadcn/ui war ich von der Idee verwirrt, dass es „kein npm-Paket” ist. Code ins Projekt kopieren? Das klang ziemlich altmodisch.

Nach ein paar Projekten wurde klar: Genau das ist der Vorteil – Sie besitzen den gesamten Komponentenquellcode, können alles anpassen, ohne Versionskonflikte oder Designvorgaben einer Bibliothek.

Heute geht es um Installation, Konfiguration und Theme-Anpassung von shadcn/ui – mit Fokus auf markenspezifische Design-Systeme über CSS-Variablen. Nach diesem Artikel sollten Sie die Grundkonfiguration in etwa 5 Minuten schaffen und danach das Theme nach Ihren Wünschen feinjustieren.


1. Schnelle Installation: Zwei Wege

Weg 1: CLI-Initialisierung (empfohlen)

Für neue Projekte direkt diesen Befehl:

npx shadcn@latest init

Die CLI stellt Fragen: TypeScript oder JavaScript? Welcher Stil? Welches Standard-Theme? Interaktiv – einfach den Hinweisen folgen.

Danach kommen typischerweise diese Dateien dazu:

  • components.json – Konfigurationsdatei
  • lib/utils.ts – Hilfsfunktionen
  • components/ui/ – Verzeichnis für Komponenten

Komponenten hinzufügen ist ebenso einfach, z. B. ein Button:

npx shadcn@latest add button

Der Code landet in components/ui/button.tsx – direkt importieren und nutzen.

Achtung: Wenn das Projekt schon weiter fortgeschritten ist, enthält tailwind.config.js und globals.css oft viel Eigenes. Der init-Befehl überschreibt diese Dateien – am besten ganz am Anfang installieren.

Ein Blogger formulierte es treffend: shadcn/ui als eine der „ersten Abhängigkeiten” behandeln, nicht erst später nachrüsten. Lehren aus der Praxis.

Weg 2: Manuelle Installation (für bestehende Projekte)

Ist das Projekt schon ausgereift, ist das Überschreiben durch die CLI riskant – dann manuell vorgehen.

Schritt 1: Tailwind CSS installieren

shadcn-Komponenten basieren auf Tailwind. Fehlt Tailwind, zuerst installieren – die offizielle Anleitung ist klar.

Schritt 2: Abhängigkeiten installieren

npm install class-variance-authority clsx tailwind-merge
npm install lucide-react

class-variance-authority (CVA) ist praktisch – später für Komponenten-Varianten.

Schritt 3: Pfad-Aliase konfigurieren

In tsconfig.json ergänzen:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]
    }
  }
}

So importieren Sie mit @/components/ui/button statt langer relativer Pfade.

Schritt 4: components.json erstellen

Im Projektroot anlegen:

{
  "style": "new-york",
  "rsc": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}

cssVariables: true ist entscheidend – Theme über CSS-Variablen statt Tailwind-Utility-Klassen.

Schritt 5: Basis-Styles hinzufügen

In globals.css die shadcn-Basis-Styles einfügen – Details folgen im Theme-Abschnitt.


2. Theme-System verstehen: CSS-Variablen

Das shadcn/ui-Theme basiert auf einer einfachen Konvention: Jede Farbe hat background- und foreground-Variablen.

Beispiel:

:root {
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
}

--primary ist die Hintergrundfarbe des Buttons, --primary-foreground die Textfarbe darauf. Eine Variable ändern – alle zugehörigen Komponenten passen sich an.

CSS-Variablen-Liste

shadcn/ui definiert standardmäßig:

VariableVerwendung
--backgroundSeitenhintergrund
--foregroundSeitentext
--cardKartenhintergrund
--card-foregroundKartentext
--popoverPopover-Hintergrund
--popover-foregroundPopover-Text
--primaryPrimärfarbe (Buttons, Links)
--primary-foregroundText auf Primärfarbe
--secondarySekundärfarbe
--secondary-foregroundText auf Sekundärfarbe
--mutedGedämpfter Hintergrund
--muted-foregroundGedämpfter Text
--accentAkzentfarbe
--accent-foregroundText auf Akzentfarbe
--destructiveGefährliche Aktion (Löschen-Button)
--destructive-foregroundText auf Destructive
--borderRahmen
--inputEingabefeld
--ringFokusring

Viele Namen – aber das background/foreground-Muster macht es leicht merkbar.

Das Geheimnis des HSL-Formats

Die Farbwerte sind nicht im Standard-HSL-Format:

/* ❌ Standard-HSL */
--primary: hsl(222.2, 47.4%, 11.2%);

/* ✅ shadcn-Format */
--primary: 222.2 47.4% 11.2%;

Warum das „nackte” Format?

Tailwind unterstützt Transparenz-Modifikatoren wie bg-primary/50 für 50 % Deckkraft. Bei vollem hsl()-Wert in der Variable funktioniert das nicht.

Im nackten Format ergänzt Tailwind automatisch hsl() und Transparenz – elegante Lösung.


3. Marken-Theme anpassen

Methode 1: CSS-Variablen direkt ändern

Am einfachsten: globals.css öffnen, :root-Abschnitt, Farbwerte anpassen.

Primärfarbe von Standard-Blau auf Lila:

:root {
  --primary: 270 60% 60%;
  --primary-foreground: 0 0% 100%;
}

.dark {
  --primary: 270 60% 70%;
  --primary-foreground: 0 0% 0%;
}

Speichern – alle Buttons und Links mit bg-primary werden lila.

Methode 2: OKLCH-Farbraum (Tailwind v4)

Mit Tailwind v4 lohnt sich OKLCH: farblich näher an menschlicher Wahrnehmung als HSL, gleichmäßigere Abstufungen.

:root {
  --primary: oklch(0.6 0.2 270);
  --primary-foreground: oklch(0.98 0 0);
}

oklch(0.6 0.2 270) bedeutet:

  • 0.6 – Helligkeit (0–1)
  • 0.2 – Sättigung (ca. 0–0,4)
  • 270 – Farbton in Grad (0–360)

Methode 3: Online-Tools

Farben selbst zusammenstellen zu mühsam? Online-Generatoren nutzen.

Empfehlung: Shadcn Theme Generator

Primärfarbe wählen – das Tool erzeugt das komplette CSS-Variablen-Set für Hell- und Dark-Mode. In globals.css einfügen.


4. Dark-Mode-Konfiguration

Theme-Umschaltung mit next-themes

shadcn/ui bringt keine Theme-Umschaltung mit – next-themes übernimmt das.

Installation:

npm install next-themes

In layout.tsx konfigurieren:

import { ThemeProvider } from "next-themes"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="de" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

Wichtige Punkte:

  • suppressHydrationWarning ist Pflicht – sonst Hydration-Warnungen
  • attribute="class" – Theme per CSS-Klasse umschalten
  • defaultTheme="system" – Standard folgt dem System
  • enableSystem – System-Theme-Erkennung aktivieren

Theme-Umschalt-Button

Mit dem useTheme-Hook aktuelles Theme und Umschaltfunktion:

import { useTheme } from "next-themes"
import { Moon, Sun } from "lucide-react"

export function ThemeToggle() {
  const { theme, setTheme } = useTheme()

  return (
    <button
      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
      className="p-2 rounded-md hover:bg-accent"
    >
      {theme === "dark" ? <Sun size={20} /> : <Moon size={20} />}
    </button>
  )
}

Standardmäßig Dark Mode

Website standardmäßig im Dark Mode – zwei Varianten:

Variante 1: dark-Klasse fest codieren

<html lang="de" className="dark">

Fest auf Dark – keine Umschaltung möglich.

Variante 2: Standard-Theme setzen

<ThemeProvider
  attribute="class"
  defaultTheme="dark"  // Standard Dark
  enableSystem={false} // System-Erkennung aus
>

Nutzer können umschalten, Startzustand ist Dark.


5. Erweiterte Anpassung: Komponenten-Varianten

Eigene Varianten mit CVA

Für Button-Stile wie „danger”, „success” oder Verläufe eignet sich CVA:

import { cva, type VariantProps } from "class-variance-authority"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

In der Komponente:

<button className={buttonVariants({ variant: "destructive", size: "lg" })}>
  Löschen
</button>

shadcn-Quellcode nicht direkt ändern

Best Practice: Obwohl der Code in Ihrem Projekt liegt, Originaldateien nicht direkt bearbeiten – stattdessen Wrapper-Komponenten.

Grund: shadcn aktualisiert Komponenten regelmäßig. Geänderte Originaldateien erfordern manuelles Mergen.

Besserer Ansatz:

// components/brand-button.tsx
import { Button } from "@/components/ui/button"
import { cva } from "class-variance-authority"

const brandButtonVariants = cva("...", {
  variants: {
    brand: {
      primary: "bg-brand-primary text-white",
      secondary: "bg-brand-secondary text-black",
    },
  },
})

export function BrandButton({ brand, ...props }) {
  return <Button className={brandButtonVariants({ brand })} {...props} />
}

Die Original-Button-Komponente bleibt unverändert – Ihre BrandButton-Anpassungen überleben shadcn-Updates.


6. Häufige Probleme und Fallstricke

Problem 1: Styles wirken nach Installation nicht

Prüfen:

  1. Wird globals.css in layout.tsx importiert?
  2. Enthält Tailwind content den Pfad components/**/*?
  3. Stimmen die Pfade in components.json?

Problem 2: Flackern beim Theme-Wechsel

Meist Hydration-Mismatch. Sicherstellen:

  1. <html> hat suppressHydrationWarning
  2. ThemeProvider umschließt die gesamte App
  3. theme nicht beim Server-Rendering auslesen (wäre undefined)

Problem 3: CSS-Variablen greifen nicht

Mögliche Ursachen:

  1. Falscher Variablenname (--primary-foreground, nicht --primaryForeground)
  2. Fehlende .dark-Styles
  3. Falsches Werteformat (nacktes HSL oder OKLCH)

Problem 4: Stilkonflikte mit bestehendem System

Bestehendes Stylesystem und shadcn können kollidieren. Lösungen:

  1. Namespace für shadcn-Komponenten (z. B. shadcn-button)
  2. Tailwind-Layer-Priorität anpassen
  3. Eigene Varianten mit CVA statt Default-Styles

7. Zusammenfassung

Installation und Konfiguration von shadcn/ui sind unkompliziert – entscheidend ist das Konzept „Code kopieren statt Paket-Abhängigkeit”. Vorteil: volle Kontrolle. Nachteil: Komponenten pro Projekt selbst pflegen.

Beim Theme ist das CSS-Variablen-System elegant: wenige Werte ändern, gesamte App-Farben passen sich an. Mit next-themes ist Hell/Dunkel-Umschaltung in wenigen Zeilen erledigt.

Empfehlungen:

  1. Neue Projekte per CLI initialisieren – weniger manuelle Konfiguration
  2. Semantische Farbvariablen wie primary, secondary statt konkreter Farbnamen
  3. Kontrast in Hell- und Dark-Mode testen – Lesbarkeit sicherstellen
  4. Wrapper-Komponenten statt Quellcode ändern – Updates bleiben einfach

Wenn Sie schnell ein UI mit Theme brauchen: shadcn/ui ausprobieren. Wer einmal Copy-and-Paste-Komponenten erlebt hat, versteht den Reiz.



Referenzen

shadcn/ui Installation und Theme-Anpassung

shadcn/ui von Grund auf installieren, Theme-System konfigurieren und markenspezifisches Design umsetzen

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Schnelle CLI-Initialisierung

    In einem neuen Projekt den Installationsbefehl ausführen:

    • npx shadcn@latest init
    • TypeScript/New-York-Stil/Standard-Theme wählen
    • Warten, bis die CLI die Konfiguration abschließt
  2. 2

    Step 2: Marken-Primärfarbe anpassen

    CSS-Variablen in globals.css bearbeiten:

    • app/globals.css öffnen
    • --primary-Variable unter :root finden
    • Auf Ihre Markenfarbe setzen (HSL- oder OKLCH-Format)
    • --primary-foreground anpassen, damit der Kontrast stimmt
  3. 3

    Step 3: Dark Mode konfigurieren

    next-themes installieren und konfigurieren:

    • npm install next-themes
    • ThemeProvider in layout.tsx einbinden
    • suppressHydrationWarning setzen, um Hydration-Warnungen zu vermeiden
    • Theme-Umschalt-Komponente erstellen
  4. 4

    Step 4: Komponenten-Varianten erstellen

    Eigene Styles mit CVA definieren:

    • class-variance-authority installieren
    • variants und defaultVariants definieren
    • buttonVariants() in der Komponente anwenden
    • Original-shadcn-Komponente unverändert lassen

FAQ

Worin unterscheidet sich shadcn/ui von klassischen UI-Komponentenbibliotheken?
shadcn/ui ist kein npm-Paket, sondern kopiert Komponentenquellcode in Ihr Projekt. Vorteil: volle Kontrolle und Anpassbarkeit, keine Versionskonflikte. Nachteil: Sie pflegen den Komponentencode pro Projekt selbst.
Warum empfiehlt sich die Installation von shadcn/ui gleich beim Projektstart?
Der init-Befehl überschreibt tailwind.config.js und globals.css. Wenn das Projekt schon weiter fortgeschritten ist, gehen bestehende Konfigurationen verloren – je früher, desto besser.
Warum CSS-Variablen im nackten Format statt als Standard-HSL?
Das nackte Format (z. B. 222.2 47.4% 11.2%) unterstützt Tailwinds Transparenz-Modifikatoren wie bg-primary/50 für 50 % Deckkraft. Bei vollem hsl()-Format funktioniert das nicht.
Wie ändere ich die Marken-Primärfarbe?
globals.css öffnen, --primary und --primary-foreground unter :root anpassen. Danach aktualisieren sich alle Komponenten mit bg-primary automatisch.
Warum flackert der Dark Mode beim Umschalten?
Meist Hydration-Mismatch. html-Tag braucht suppressHydrationWarning, ThemeProvider muss die gesamte App umschließen, theme nicht beim Server-Rendering auslesen.
Soll ich shadcn-Komponentenquellcode direkt ändern?
Nicht empfohlen. shadcn aktualisiert Komponenten häufig – geänderte Originaldateien erfordern manuelles Mergen. Besser: Wrapper-Komponenten erstellen und Original unverändert lassen.

7 Min. Lesezeit · Veröffentlicht am: 26. März 2026 · Aktualisiert am: 13. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog