ui.shadcn.com: Ein ausführlicher Leitfaden zu shadcn/ui
shadcn/ui — erreichbar über ui.shadcn.com — gehört zu den einflussreichsten Werkzeugen im modernen React- und Tailwind-Ökosystem. Es wird oft als Komponentenbibliothek bezeichnet, unterscheidet sich aber grundlegend von klassischen UI-Libraries wie Material UI, Ant Design oder Chakra UI.
Der wichtigste Gedanke lautet:
shadcn/ui installiert keine fremde Design-Bibliothek in das Projekt. Es bringt den Quellcode der gewünschten Komponenten direkt in das eigene Repository.
Diese Idee verändert, wie Teams Komponenten auswählen, gestalten, warten und langfristig kontrollieren. Statt eine Black Box mit vorgegebenen Abstraktionen zu verwenden, erhält man zugänglichen, anpassbaren Code — typischerweise auf Basis von React, Tailwind CSS, Radix UI und TypeScript.
Was ist shadcn/ui?
shadcn/ui ist eine Sammlung hochwertiger, zugänglicher und anpassbarer UI-Komponenten sowie zugehöriger Werkzeuge. Die Website bietet unter anderem:
- Komponenten wie Buttons, Dialoge, Formulare und Menüs,
- Layout- und Anwendungsbausteine,
- vorgefertigte Themes und Farbkonfigurationen,
- Beispiele und vollständige Seitenmuster,
- eine CLI für Installation und Code-Generierung,
- ein Registry-System für externe Komponentenquellen,
- Dokumentation zu Architektur, Styling und Best Practices.
Die Komponenten richten sich vor allem an Projekte mit:
- React
- Next.js
- Tailwind CSS
- TypeScript
- gegebenenfalls React Hook Form, Zod, Radix UI und ähnlichen Werkzeugen.
Inzwischen existieren außerdem Integrations- und Anpassungsmöglichkeiten für weitere Frameworks und Setups. Die konkrete Auswahl sollte jedoch stets anhand der aktuellen Dokumentation auf ui.shadcn.com geprüft werden, da das Ökosystem aktiv weiterentwickelt wird.
Die zentrale Besonderheit: Kein klassisches npm-UI-Paket
Bei einer traditionellen Komponentenbibliothek sieht die Nutzung häufig so aus:
import { Button } from "some-ui-library"
export function SaveButton() {
return <Button variant="primary">Speichern</Button>
}
Das ist komfortabel, hat aber Konsequenzen:
- Das Verhalten der Komponente hängt von einer externen Paketversion ab.
- Tiefgreifende Änderungen können schwierig sein.
- Das Styling folgt oft dem System der Bibliothek.
- Updates können Breaking Changes auslösen.
- Eine Komponente enthält manchmal mehr Abstraktion, Code oder Styling-System als benötigt.
Bei shadcn/ui erfolgt der Ablauf anders. Man fügt beispielsweise einen Button über die CLI hinzu:
npx shadcn@latest add button
Danach liegt der Komponentenquellcode im eigenen Projekt, etwa in einer Struktur wie:
components/
└── ui/
└── button.tsx
Die Anwendung importiert anschließend die eigene lokale Datei:
import { Button } from "@/components/ui/button"
export function SaveButton() {
return <Button>Speichern</Button>
}
Die Datei gehört nun zum Projekt. Entwicklerinnen und Entwickler können sie:
- lesen,
- verändern,
- vereinfachen,
- erweitern,
- umbenennen,
- versionieren,
- testen,
- bei Bedarf vollständig ersetzen.
Das ist der Kern des Konzepts.
„Open Code“ statt „Open Source Library“
shadcn/ui wird häufig mit dem Ausdruck Open Code verbunden. Damit ist nicht nur gemeint, dass Quellcode sichtbar ist. Gemeint ist vielmehr ein bestimmtes Nutzungsmodell:
- Eine Komponente wird aus einem bekannten, gepflegten Ausgangspunkt übernommen.
- Der Code wird direkt im eigenen Repository abgelegt.
- Das Team übernimmt bewusst Verantwortung für diesen Code.
- Das Design-System entwickelt sich gemeinsam mit der Anwendung weiter.
Eine klassische Library bietet meist eine API, die man konsumiert. shadcn/ui liefert dagegen eher ein ausgearbeitetes Startmaterial.
Diese Philosophie passt gut zu Teams, die ihr Interface als Teil ihres Produkts verstehen — nicht als austauschbare Darstellungsschicht.
Die technische Grundlage
shadcn/ui setzt nicht auf eine einzige technische Abstraktion. Vielmehr kombiniert es mehrere etablierte Werkzeuge.
React als Komponentenmodell
Die meisten shadcn/ui-Komponenten werden als React-Komponenten bereitgestellt. Das macht sie besonders geeignet für moderne Web-Anwendungen mit:
- Next.js,
- Vite,
- React Router,
- serverseitigem Rendering,
- Client Components,
- TypeScript.
Die Komponenten sind gewöhnlich klein genug, um nachvollziehbar zu bleiben, aber vollständig genug, um produktive Anwendungsfälle abzudecken.
Tailwind CSS für Styling
Das visuelle Styling basiert in der Regel auf Tailwind CSS. Statt große CSS-Dateien mit komplexer Selektorspezifität zu pflegen, werden Utility-Klassen direkt an Komponenten verwendet.
Ein vereinfachtes Beispiel:
<button
className="
inline-flex items-center justify-center rounded-md
bg-primary px-4 py-2 text-sm font-medium text-primary-foreground
transition-colors hover:bg-primary/90
focus-visible:outline-none focus-visible:ring-2
disabled:pointer-events-none disabled:opacity-50
"
>
Speichern
</button>
Die tatsächlichen Komponenten enthalten häufig zusätzliche Logik, etwa für Varianten, Größen, Zustände und Barrierefreiheit. Der grundsätzliche Stil bleibt jedoch sichtbar und nachvollziehbar.
Vorteile von Tailwind in diesem Kontext
- Schnelle visuelle Anpassungen direkt im Komponenten-Code
- Keine zwingende Abhängigkeit von komplexen CSS-in-JS-Systemen
- Gute Verbindung zu Design Tokens über CSS-Variablen
- Konsistente Abstände, Typografie und Farbwerte
- Einfache Erkennung ungenutzter Styles im Build-Prozess
- Gute Zusammenarbeit mit Variantenwerkzeugen wie
class-variance-authority
Mögliche Nachteile
- Lange
className-Attribute können zunächst unübersichtlich wirken. - Teams ohne Tailwind-Erfahrung benötigen Einarbeitung.
- Sehr individuelle visuelle Regeln sollten nicht unkontrolliert über viele Komponenten verteilt werden.
- Ohne klare Konventionen kann Utility-CSS inkonsistent eingesetzt werden.
shadcn/ui löst dieses Problem nicht automatisch. Es gibt Teams jedoch eine gute Ausgangsstruktur, um konsistente Regeln aufzubauen.
Radix UI für Zugänglichkeit und Interaktion
Viele komplexere Komponenten von shadcn/ui bauen auf Radix UI Primitives auf. Radix bietet sogenannte „headless“ oder ungestylte Bausteine für Interaktionen wie:
- Dialoge,
- Dropdown-Menüs,
- Popover,
- Tabs,
- Tooltips,
- Select-Felder,
- Kontextmenüs,
- Akkordeons,
- Menüs,
- Alert Dialogs.
„Headless“ bedeutet in diesem Zusammenhang: Die Logik und Zugänglichkeit sind vorhanden, das visuelle Styling wird jedoch nicht vollständig vorgegeben.
Ein Dialog benötigt beispielsweise mehr als nur ein sichtbar eingeblendetes Element. Er muss unter anderem:
- beim Öffnen sinnvoll fokussiert werden,
- den Tastaturfokus innerhalb des Dialogs halten,
- mit der Escape-Taste schließen können,
- für Screenreader korrekt ausgezeichnet sein,
- Hintergrundinteraktionen angemessen behandeln,
- beim Schließen den Fokus zurückgeben,
- Rollen und ARIA-Attribute korrekt setzen.
Radix UI nimmt bei vielen solchen Problemen einen erheblichen Teil der Arbeit ab. shadcn/ui ergänzt darauf ein konkretes, modernes Design und stellt den vollständigen Integrationscode bereit.
TypeScript für robuste Komponenten-APIs
Die Komponenten sind in der Regel mit TypeScript geschrieben. Das hilft bei:
- Autovervollständigung im Editor,
- verständlichen Props,
- früher Erkennung falscher Übergabewerte,
- sauberer Weitergabe nativer HTML-Attribute,
- Typsicherheit bei Varianten und Events.
<Button
variant="destructive"
size="sm"
disabled
onClick={() => {
console.log("Löschen")
}}
>
Löschen
</Button>
Das Ziel ist nicht, eine besonders komplizierte API zu schaffen, sondern eine vertraute, eng an HTML und React orientierte Schnittstelle bereitzustellen.
Das Design-System hinter shadcn/ui
shadcn/ui ist nicht nur eine Ansammlung isolierter Komponenten. Die Komponenten folgen einer gemeinsamen Designsprache. Sie basiert typischerweise auf:
- neutralen Grundfarben,
- klaren Kontrasten,
- zurückhaltenden Schatten,
- abgerundeten Ecken,
- konsistenten Abständen,
- verständlicher Typografie,
- sichtbaren Fokuszuständen,
- hellen und dunklen Oberflächen,
- semantischen Farbrollen.
Das Resultat wirkt meist modern, produktiv und eher neutral als stark markenorientiert. Genau das ist eine Stärke: Das Ausgangsdesign ist professionell, ohne die Produktidentität vollständig vorwegzunehmen.
Semantische Design Tokens
Ein zentraler Teil des Systems sind semantische Farbvariablen. Statt überall konkrete Farbwerte zu verwenden, werden Rollen definiert.
Beispielhaft könnte eine Konfiguration so aussehen:
:root {
--background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
}
Die konkrete Syntax kann je nach Setup, Tailwind-Version und shadcn/ui-Konfiguration variieren. Entscheidend ist das Prinzip:
--primarysteht für die primäre Marken- oder Aktionsfarbe.--destructivekennzeichnet riskante Handlungen wie Löschen.--mutedrepräsentiert zurückhaltende Flächen oder Texte.--borderdefiniert die Standardrahmenfarbe.--ringsteuert häufig den sichtbaren Fokusindikator.
className="bg-primary text-primary-foreground"
Dadurch lässt sich das gesamte Erscheinungsbild kontrolliert ändern, ohne jede einzelne Komponente manuell überarbeiten zu müssen.
Dark Mode
Ein großer Vorteil des Token-Ansatzes ist die Unterstützung eines Dark Modes. Statt Komponenten separat umzustylen, werden primär die Variablen der dunklen Umgebung neu definiert.
Vereinfacht:
.dark {
--background: 222.2 47.4% 11.2%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--border: 217.2 32.6% 17.5%;
}
Wenn Komponenten konsequent semantische Rollen verwenden, reagieren sie automatisch auf den Wechsel zwischen hellem und dunklem Theme.
Das bedeutet jedoch nicht, dass Dark Mode ohne Prüfung fertig ist. Besonders geprüft werden sollten:
- Kontrast von Texten,
- subtile Rahmen,
- deaktivierte Zustände,
- Diagrammfarben,
- Status-Badges,
- Bilder und Logos,
- Schatten,
- Hover- und Fokuszustände.
Die CLI: Komponenten gezielt in das Projekt übernehmen
Die shadcn-CLI ist eines der wichtigsten Werkzeuge des Projekts. Sie unterstützt bei der Einrichtung und beim Hinzufügen von Komponenten.
Ein typischer Ablauf beginnt mit einer Initialisierung:
npx shadcn@latest init
Je nach Projekt fragt die CLI Konfigurationsdetails ab, etwa:
- Wo liegen Komponenten?
- Wo liegt die globale CSS-Datei?
- Welcher Import-Alias wird verwendet?
- Welche Basisfarbe soll verwendet werden?
- Soll CSS-Variablen-basiertes Theming verwendet werden?
- Welche Komponenten- oder Utility-Verzeichnisse existieren bereits?
Anschließend können Komponenten einzeln ergänzt werden:
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add form
npx shadcn@latest add table
Mehrere Komponenten lassen sich je nach CLI-Version und Konfiguration oft auch gemeinsam hinzufügen:
npx shadcn@latest add button input label textarea
Was die CLI normalerweise erledigt
Beim Hinzufügen einer Komponente kann die CLI unter anderem:
- Komponenten-Dateien kopieren oder erzeugen.
- Fehlende Paketabhängigkeiten installieren.
- Hilfsfunktionen ergänzen.
- Importpfade auf die Projektstruktur abstimmen.
- Benötigte Primitive oder Utilities berücksichtigen.
- Tailwind-kompatible Klassen und Varianten übernehmen.
Die CLI ist damit kein Runtime-System und keine Magie im Browser. Sie ist ein Projektgenerator. Nach dem Generieren ist der erzeugte Code regulärer Projektcode.
Die Konfigurationsdatei
shadcn/ui verwendet typischerweise eine Konfigurationsdatei wie components.json. Sie beschreibt, wie die CLI das Projekt interpretieren soll.
Vereinfacht könnte eine solche Datei so aussehen:
{
"style": "default",
"tsx": true,
"rsc": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui"
}
}
Die tatsächlichen Optionen und Werte können sich weiterentwickeln. Inhaltlich erfüllt die Datei aber eine wichtige Funktion: Sie macht die Generierung reproduzierbar und an die Architektur des jeweiligen Projekts anpassbar.
Die wichtigsten Komponentenarten
ui.shadcn.com stellt zahlreiche Bausteine bereit. Ihre genaue Auswahl kann sich über die Zeit ändern, aber sie lässt sich sinnvoll in Kategorien einteilen.
Grundlegende Eingabe- und Aktionskomponenten
Diese Komponenten bilden die Basis fast jeder Anwendung:
Sie sind besonders nützlich, weil Formulare sehr schnell inkonsistent werden können. Unterschiedliche Rahmenstärken, Höhen, Fokuszustände oder Fehlermeldungen wirken in einer Anwendung sofort unprofessionell.
Overlay- und Dialogkomponenten
Overlays sind interaktiv anspruchsvoll und profitieren besonders stark von zugrunde liegenden Accessibility-Primitives:
- Dialog
- Alert Dialog
- Sheet
- Drawer
- Popover
- Tooltip
- Hover Card
- Context Menu
- Dropdown Menu
Ein Dialog eignet sich beispielsweise für längere Interaktionen, etwa zum Bearbeiten eines Profils. Ein Alert Dialog ist für Entscheidungen mit Folgen gedacht, etwa:
„Möchten Sie dieses Projekt wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.“
Ein Sheet erscheint häufig seitlich am Bildschirmrand und eignet sich für:
Navigationskomponenten
Für den Aufbau strukturierter Anwendungen sind Navigationsmuster zentral:
Die Command-Komponente ist besonders interessant. Sie dient häufig als Grundlage für Command Palettes, also Such- und Aktionsoberflächen ähnlich wie in Entwicklerwerkzeugen oder Produktivitäts-Apps.
Beispiele für mögliche Aktionen:
Projekt öffnen
Neue Rechnung erstellen
Zum Dashboard wechseln
Einstellungen durchsuchen
Teammitglied einladen
In Kombination mit einer Tastenkombination wie ⌘ K oder Ctrl K entsteht ein modernes, schnelles Bedienkonzept.
Informations- und Statuskomponenten
Diese Komponenten helfen, Inhalte übersichtlich darzustellen:
- Card
- Badge
- Alert
- Avatar
- Skeleton
- Progress
- Separator
- Table
- Data Table, oft als Beispielarchitektur
- Sonner oder Toast-Komponente
- Accordion
- Collapsible
- Scroll Area
Ein Skeleton verbessert beispielsweise die wahrgenommene Ladezeit. Statt leerer Flächen zeigt die Anwendung eine visuelle Vorschau der noch ladenden Struktur.
<div className="space-y-3">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
<Skeleton className="h-24 w-full" />
</div>
Varianten mit class-variance-authority
Viele shadcn/ui-Komponenten verwenden häufig class-variance-authority, kurz CVA. Dieses Werkzeug hilft dabei, Varianten nicht über verschachtelte Bedingungen im JSX zu verteilen.
Ein vereinfachtes Beispiel für Button-Varianten:
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent",
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"
}
}
)
Die Komponente kann dann mit klaren, typisierten Varianten verwendet werden:
<Button variant="outline" size="sm">
Abbrechen
</Button>
Das verhindert, dass jede Seite eigene Klassen für Standardfälle erfindet. Gleichzeitig bleibt die gesamte Implementierung lokal und editierbar.
Die Utility cn()
In vielen shadcn/ui-Projekten existiert eine Hilfsfunktion namens cn. Sie kombiniert häufig Werkzeuge wie clsx und tailwind-merge.
Ein mögliches Muster:
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Sie ermöglicht, Standardklassen mit zusätzlichen Klassen zusammenzuführen:
<Card className="border-primary/30 shadow-lg">
<CardContent>Inhalt</CardContent>
</Card>
Der entscheidende Nutzen liegt darin, dass widersprüchliche Tailwind-Klassen besser behandelt werden können. Wenn eine Komponente etwa standardmäßig p-4 besitzt und der Aufrufer p-8 übergibt, kann tailwind-merge in vielen Fällen die widersprüchliche Klasse sinnvoll auflösen.
Formulare mit shadcn/ui
Formulare gehören zu den häufigsten und anspruchsvollsten Teilen einer Web-Anwendung. Sie verbinden:
- Eingabekomponenten,
- Validierung,
- Fehlermeldungen,
- Labels,
- Hilfetexte,
- Ladezustände,
- serverseitige Verarbeitung,
- Zugänglichkeit.
shadcn/ui wird häufig zusammen mit React Hook Form und Zod verwendet.
- React Hook Form verwaltet Formularzustände effizient.
- Zod beschreibt und validiert Datenstrukturen.
- shadcn/ui liefert die visuelle und strukturelle Form-Schicht.
Ein vereinfachtes Schema könnte so aussehen:
import { z } from "zod"
const profileSchema = z.object({
name: z.string().min(2, {
message: "Der Name muss mindestens zwei Zeichen enthalten."
}),
email: z.string().email({
message: "Bitte geben Sie eine gültige E-Mail-Adresse ein."
})
})
Das Formular kann dann Eingabefelder, Labels und Fehlermeldungen konsistent darstellen:
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>E-Mail-Adresse</FormLabel>
<FormControl>
<Input placeholder="name@beispiel.de" {...field} />
</FormControl>
<FormDescription>
Diese Adresse wird für wichtige Benachrichtigungen verwendet.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
Warum diese Kombination praktisch ist
Ohne Struktur entstehen Formulare oft so:
<label>E-Mail</label>
<input />
{error && <span className="text-red-500">{error}</span>}
Das funktioniert für ein Feld, wird aber bei 20 Formularen und mehreren Teams schnell inkonsistent. Mit einem einheitlichen Muster lassen sich:
- Label-Abstände,
- Fehlermeldungen,
- Beschreibungen,
- ARIA-Beziehungen,
- Validierungszustände,
- visuelle Fehlerbehandlung
verlässlicher standardisieren.
Data Tables: leistungsfähig, aber kein Plug-and-Play-Wunder
Ein besonders beliebtes Thema im shadcn/ui-Umfeld sind Daten-Tabellen. Häufig wird dafür TanStack Table verwendet.
Tabellen in professionellen Anwendungen benötigen oft deutlich mehr als eine HTML-Tabelle:
- Sortierung,
- Filter,
- Volltextsuche,
- Spaltenauswahl,
- Paginierung,
- Zeilenauswahl,
- Bulk-Aktionen,
- serverseitige Datenabfragen,
- responsive Darstellung,
- Export,
- leere Zustände,
- Ladezustände.
shadcn/ui bietet hierfür eher ein Architektur- und Komponentenbeispiel als eine vollständig vorkonfigurierte Enterprise-Tabelle.
Das ist ein wichtiger Unterschied.
Eine Data Table auf Basis von shadcn/ui kann sehr mächtig werden, aber das Team muss bewusst entscheiden:
- Welche Filterlogik ist nötig?
- Erfolgt Pagination auf Client oder Server?
- Wie werden Tabellenparameter in der URL gespeichert?
- Wie sieht die mobile Alternative aus?
- Welche Spalten sind für welche Rollen sichtbar?
- Wie werden große Datenmengen effizient geladen?
- Wie werden Rechte und Aktionen abgesichert?
Für ein Admin-Dashboard ist diese Flexibilität hervorragend. Für ein kleines Projekt, das nur schnell eine statische Tabelle benötigt, kann sie unnötig komplex sein.
Beispiele, Blocks und Anwendungsoberflächen
Neben einzelnen Komponenten sind auf ui.shadcn.com häufig auch größere Bausteine und Vorlagen zu finden. Dazu können gehören:
- Login- und Registrierungsseiten,
- Dashboards,
- Seitenleisten,
- Einstellungsansichten,
- Profilseiten,
- Marketing-Abschnitte,
- Checkout- oder Formularabläufe,
- Tabellenoberflächen,
- Kalenderansichten,
- E-Commerce-Muster,
- Kommunikations- oder Dokumentationslayouts.
Solche Vorlagen sind wertvoll, weil sie nicht nur Einzelteile zeigen, sondern deren Zusammenspiel:
- Welche Abstände funktionieren zwischen Card, Titel und Beschreibung?
- Wie werden Tabellenaktionen platziert?
- Wie sieht eine responsive Sidebar aus?
- Wie werden Filter in einer mobilen Ansicht dargestellt?
- Wie verbindet man Tabs, Dialoge und Tabellen zu einer nachvollziehbaren Oberfläche?
Für viele Teams spart dies erheblich Zeit in der frühen Produktphase.
Das Registry-Konzept
Ein fortgeschrittenes Konzept von shadcn/ui ist das Registry-System. Eine Registry ist vereinfacht eine Quelle, aus der Komponenten, Blöcke, Utilities oder andere Projektbausteine bezogen werden können.
Das kann über die offizielle Registry hinausgehen. Organisationen können beispielsweise interne Komponenten bereitstellen:
- Corporate-Design-Komponenten,
- Brand-spezifische Buttons,
- Authentifizierungsformulare,
- interne Dashboard-Widgets,
- Analytics-Karten,
- Domain-spezifische Formulare,
- wiederverwendbare Feature-Bausteine.
Ein Team könnte so eine interne Komponente bereitstellen:
@company/customer-status-card
Und sie projektübergreifend beziehen:
npx shadcn@latest add @company/customer-status-card
Die genaue Syntax und Registry-Konfiguration hängt von der jeweiligen shadcn-Version und Registry-Einrichtung ab. Strategisch ist der Gedanke aber sehr bedeutend:
Ein Unternehmen kann seine eigene Komponentenversorgung aufbauen, ohne zwingend eine umfangreiche, zur Laufzeit eingebundene UI-Library veröffentlichen zu müssen.
Nutzen interner Registries
Interne Registries können insbesondere bei mehreren Anwendungen helfen:
- Einheitliches Branding
- Schneller Projektstart
- Wiederverwendung bewährter Patterns
- Weniger Copy-and-Paste zwischen Repositories
- Einheitliche Accessibility-Standards
- Gemeinsame Basiskomponenten
- Nachvollziehbare technische Konventionen
Dabei muss bewusst entschieden werden, wie Updates funktionieren. Da Code in Zielprojekte kopiert wird, gibt es nicht automatisch ein zentrales Runtime-Update wie bei einem npm-Paket.
Das kann Vor- und Nachteile haben.
Updates: Freiheit bedeutet Verantwortung
Ein häufiger Irrtum lautet:
„Wenn ich shadcn/ui nutze, aktualisieren sich meine Komponenten automatisch.“
Das ist gerade nicht das Grundmodell.
Sobald eine Komponente in das eigene Projekt übernommen wurde, ist sie Teil des eigenen Codes. Wenn später eine neue Version der Vorlage, ein Bugfix oder eine Accessibility-Verbesserung erscheint, muss das Team entscheiden:
- Ist die Änderung relevant?
- Wurde die lokale Komponente bereits angepasst?
- Kann der Unterschied übernommen werden?
- Gibt es Tests für das bisherige Verhalten?
- Entsteht ein Konflikt mit dem eigenen Design-System?
Diese Verantwortung ist nicht grundsätzlich schlecht. Sie entspricht der zentralen Idee von Code Ownership. Sie bedeutet aber, dass shadcn/ui kein „installieren und für immer vergessen“-Werkzeug ist.
Sinnvolle Update-Strategie
Für produktive Anwendungen empfiehlt sich ein bewusster Prozess:
-
Komponenten nicht unnötig früh forken
Nur ändern, wenn es einen echten Produkt- oder Designgrund gibt. -
Eigene Anpassungen dokumentieren
Kommentare oder Changelogs helfen, lokale Abweichungen zu verstehen. -
Kritische Komponenten testen
Besonders Dialoge, Menüs, Formulare und Authentifizierungsoberflächen. -
Upstream-Änderungen regelmäßig prüfen
Nicht jede Änderung muss übernommen werden, aber relevante Fixes sollten sichtbar sein. -
Design Tokens zentral halten
Möglichst Farben, Rundungen und Abstände nicht in jeder Komponente individuell verändern. -
Kompositionsschicht einführen
Produkt-spezifische Komponenten wieDeleteProjectDialogsollten über generischen UI-Komponenten liegen.
Empfohlene Projektarchitektur
Eine einfache, gut skalierbare Struktur könnte so aussehen:
app/
dashboard/
settings/
projects/
components/
ui/
button.tsx
card.tsx
dialog.tsx
input.tsx
table.tsx
layout/
app-sidebar.tsx
dashboard-header.tsx
projects/
project-card.tsx
project-status-badge.tsx
delete-project-dialog.tsx
lib/
utils.ts
validations/
project.ts
hooks/
use-project-filters.ts
Die Rollen dieser Ebenen
components/ui
Hier liegen die generischen, möglichst produktneutralen shadcn/ui-Bausteine:
Diese Komponenten sollten nur selten fachliche Begriffe wie „Rechnung“, „Kunde“ oder „Projektstatus“ kennen.
components/layout
Diese Ebene enthält wiederkehrende Seitenstrukturen:
Fachliche Komponenten
Hier liegen Komponenten mit Geschäftslogik oder Domänenwissen:
InvoiceStatusBadgeCustomerDetailsCardDeleteProjectDialogOrderTimelineUserRoleSelect
Diese Schicht komponiert die generischen UI-Bausteine zu produktrelevanten Funktionen.
Ein praktisches Beispiel: fachliche Komposition
Statt einen allgemeinen Dialog überall neu zusammenzusetzen, kann eine fachliche Komponente entstehen:
import { Button } from "@/components/ui/button"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger
} from "@/components/ui/alert-dialog"
type DeleteProjectDialogProps = {
projectName: string
onConfirm: () => void
}
export function DeleteProjectDialog({
projectName,
onConfirm
}: DeleteProjectDialogProps) {
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Projekt löschen</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Projekt wirklich löschen?</AlertDialogTitle>
<AlertDialogDescription>
Das Projekt „{projectName}“ wird dauerhaft gelöscht. Diese Aktion
kann nicht rückgängig gemacht werden.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Abbrechen</AlertDialogCancel>
<AlertDialogAction onClick={onConfirm}>
Endgültig löschen
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}
Die UI-Komponenten bleiben allgemein. Die Domänenkomponente formuliert dagegen die konkrete Produktsprache und das konkrete Verhalten.
Das macht die Anwendung leichter wartbar und übersetzbar.
Zugänglichkeit: Eine starke Grundlage, keine automatische Garantie
shadcn/ui und Radix UI können die Zugänglichkeit deutlich verbessern. Sie liefern oft solide Mechanismen für:
- Tastatursteuerung,
- Fokusmanagement,
- semantische Rollen,
- ARIA-Attribute,
- Interaktionszustände,
- Escape-Verhalten,
- zugängliche Overlays.
Aber: Zugänglichkeit kann nicht vollständig durch eine Komponentenbibliothek garantiert werden.
Folgende Fehler können trotz guter Komponentenbasis entstehen:
<Button variant="ghost" size="icon" aria-label="Benachrichtigungen öffnen">
<BellIcon />
</Button>
Nicht ausreichend wäre:
<Button variant="ghost" size="icon">
<BellIcon />
</Button>
Für sehende Nutzerinnen und Nutzer mag das Symbol verständlich sein. Für Screenreader fehlt jedoch die Information, was der Button auslöst.
Vorteile von shadcn/ui
Volle Kontrolle über den Code
Die wichtigste Stärke ist die lokale Eigentümerschaft. Teams können jede Komponente anpassen, ohne auf Erweiterungspunkte einer externen Library warten zu müssen.
Das ist besonders wertvoll bei:
- starkem Branding,
- ungewöhnlichen Produktanforderungen,
- langfristigen Anwendungen,
- Design-Systemen mit eigenen Regeln,
- komplexen UI-Workflows.
Moderne, hochwertige Ausgangsbasis
Die Komponenten wirken typischerweise:
- klar,
- zurückhaltend,
- professionell,
- responsive,
- produktorientiert,
- nah an aktuellen SaaS- und Dashboard-Oberflächen.
Dadurch lassen sich MVPs und produktive Anwendungen schnell mit einer glaubwürdigen visuellen Qualität umsetzen.
Gute Kombinierbarkeit
Da shadcn/ui auf bekannten Web- und React-Konzepten basiert, lässt es sich gut mit anderen Werkzeugen verbinden:
- React Hook Form
- Zod
- TanStack Table
- TanStack Query
- Next.js Server Actions
- Zustand
- Redux Toolkit
- Framer Motion
- Lucide Icons
- Authentifizierungsanbieter
- Datenbanken und ORM-Lösungen
shadcn/ui versucht nicht, das gesamte Anwendungsökosystem selbst zu kontrollieren.
Weniger Vendor Lock-in auf Komponentenebene
Wenn eine klassische UI-Library nicht mehr passt, kann ein Wechsel teuer werden. Bei shadcn/ui liegt der relevante Code bereits im Projekt.
Natürlich bleiben Abhängigkeiten wie React, Tailwind oder Radix UI bestehen. Dennoch ist die visuelle und strukturelle Komponentenschicht weniger an eine zentrale UI-Library gebunden.
Gute Lernwirkung
Der Code eignet sich hervorragend, um moderne UI-Patterns zu verstehen:
- Wie werden Varianten modelliert?
- Wie werden Dialoge strukturiert?
- Wie funktionieren
forwardRefund prop-basierte APIs? - Wie werden Tailwind-Klassen sinnvoll kombiniert?
- Wie baut man zugängliche Popover?
- Wie trennt man primitive und fachliche Komponenten?
Für viele Entwicklerinnen und Entwickler ist shadcn/ui deshalb nicht nur ein Werkzeug, sondern auch eine Lernressource.
Nachteile und Grenzen
Kein vollständig automatisiertes Update-Modell
Lokaler Code bringt Verantwortung. Wer ein sehr zentrales, automatisch versioniertes Component Package mit kontrollierten Upgrades sucht, muss eine zusätzliche Strategie aufbauen oder eventuell eine klassische Library bevorzugen.
Tailwind ist praktisch eine Kernannahme
Wer Tailwind CSS nicht einsetzen möchte, wird mit shadcn/ui deutlich weniger Freude haben. Die Komponenten lassen sich zwar umschreiben, aber dann verliert man einen zentralen Vorteil der Ausgangsbasis.
Nicht jede Komponente ist sofort eine Produktlösung
Einige Bausteine sind bewusst Beispiele oder Ausgangspunkte. Besonders bei komplexen Themen wie:
- Daten-Tabellen,
- Kalendern,
- Rich-Text-Editoren,
- Dateiuploads,
- Multi-Step-Wizards,
- Autocomplete-Feldern,
- internationalisierten Datumsformaten,
- komplexen Berechtigungssystemen
reicht das Kopieren einer Komponente nicht aus. Fachlogik, Performance, Sicherheit und UX müssen weiterhin sorgfältig entwickelt werden.
Konsistenz kann ohne Governance leiden
Die leichte Änderbarkeit kann auch problematisch sein. Wenn jedes Teammitglied Button, Input und Card spontan anders verändert, zerfällt das Design-System.
Hilfreich sind deshalb:
- Code Reviews,
- dokumentierte Design Tokens,
- klare Ownership,
- visuelle Regressionstests,
- Storybook oder ähnliche Komponenten-Dokumentation,
- Design- und Entwicklungsrichtlinien,
- feste Regeln für neue Varianten.
shadcn/ui im Vergleich zu klassischen UI-Libraries
Die folgende Übersicht zeigt die unterschiedlichen Denkmodelle:
| Aspekt | shadcn/ui | Klassische UI-Library |
|---|---|---|
| Bereitstellung | Komponenten-Code wird ins Projekt übernommen | Komponenten werden aus einem Paket importiert |
| Ownership | Team besitzt und pflegt den Code | Library-Anbieter pflegt den Kerncode |
| Anpassbarkeit | Sehr hoch | Abhängig von Theme- und Override-System |
| Updates | Bewusste Übernahme nötig | Paketupdate kann Änderungen bringen |
| Design-Vorgaben | Moderne Basis, leicht anpassbar | Häufig stärker durch Library geprägt |
| Abstraktionsgrad | Eher niedrig bis mittel | Häufig mittel bis hoch |
| Einstieg | Tailwind- und React-Kenntnisse hilfreich | Oft schneller bei Standardfällen |
| Langfristige Freiheit | Hoch | Kann stärker an Anbieter-API binden |
| Konsistenz ohne Regeln | Muss intern organisiert werden | Wird stärker durch Library erzwungen |
Keine der beiden Strategien ist grundsätzlich überlegen.
Eine klassische Library ist oft sinnvoll, wenn:
- ein Team sehr schnell mit Standardoberflächen starten muss,
- wenig Kapazität für UI-Ownership vorhanden ist,
- starke zentrale Vorgaben akzeptabel sind,
- viele sofort fertige Enterprise-Komponenten benötigt werden.
shadcn/ui ist besonders passend, wenn:
- UI und Markenidentität wichtig sind,
- Tailwind bereits eingesetzt wird,
- React-Erfahrung vorhanden ist,
- Komponenten langfristig kontrolliert werden sollen,
- Teams eine eigene Design-System-Schicht aufbauen möchten.
Für welche Projekte eignet sich shadcn/ui?
Sehr gut geeignet für
- SaaS-Produkte
- Admin-Dashboards
- interne Unternehmenswerkzeuge
- B2B-Anwendungen
- moderne Web-Apps
- Entwicklerplattformen
- Kundenportale
- MVPs mit Anspruch auf gutes UI
- Start-ups mit wachsendem Design-System
- Next.js- und React-Anwendungen
- Produkte mit individuellem Branding
Mit Bedacht einsetzen bei
- Projekten ohne React oder Tailwind
- Teams ohne Bereitschaft zur Komponentenpflege
- Anwendungen, die ein sofort vollständig vorkonfiguriertes Enterprise-Design benötigen
- stark regulierten Anwendungen ohne etablierten Accessibility- und Testprozess
- Teams, die zentrale Updates für Hunderte Anwendungen ohne eigenen Registry- oder Paketprozess erwarten
Best Practices für produktive Projekte
1. Nicht jede Komponente sofort verändern
Die Standardkomponenten sind bewusst generisch. Es ist oft besser, zuerst mit den vorhandenen Varianten zu arbeiten und Anpassungen erst vorzunehmen, wenn echte Anforderungen bestehen.
2. Tokens vor Einzelklassen ändern
Wenn die Markenfarbe geändert werden soll, ist dies besser über semantische Tokens als über dutzende einzelne bg-blue-*-Klassen zu lösen.
Schlecht:
<Button className="bg-purple-600 hover:bg-purple-700">
Speichern
</Button>
Besser:
<Button>Speichern</Button>
Und die semantische Primärfarbe zentral definieren.
3. Produktkomponenten über UI-Primitives bauen
export function InviteMemberButton() {
return (
<Button>
Mitglied einladen
</Button>
)
}
Wenn später Berechtigungen, Analytics oder ein Dialog ergänzt werden, bleibt die Logik an einem fachlich passenden Ort.
4. Varianten begrenzen
Es ist verlockend, für jede neue visuelle Idee eine Button-Variante anzulegen:
primary
secondary
subtle
inverse
brand
marketing
premium
warning
highlight
neon
Das führt langfristig zu einem unklaren System. Besser sind wenige semantische Varianten, beispielsweise:
defaultsecondaryoutlineghostdestructivelink
Neue Varianten sollten nur entstehen, wenn sie eine wiederkehrende, klar definierte Bedeutung besitzen.
5. Accessibility und mobile Nutzung testen
Insbesondere bei diesen Komponenten sollte man nicht nur mit der Maus testen:
Ein Mindesttest sollte umfassen:
- Bedienung mit Tab und Shift+Tab
- Aktivierung mit Enter und Leertaste
- Schließen von Overlays mit Escape
- Sichtbare Fokuszustände
- sinnvolle Screenreader-Beschriftungen
- ausreichende Farbkontraste
- Bedienbarkeit auf kleinen Bildschirmen
6. Komponenten mit echten Inhalten prüfen
Platzhaltertexte täuschen oft über Layoutprobleme hinweg. Testdaten sollten enthalten:
- sehr lange Namen,
- leere Werte,
- Sonderzeichen,
- mehrere Sprachen,
- sehr kurze und sehr lange Statuswerte,
- Fehlermeldungen,
- nicht verfügbare Aktionen,
- Lade- und Fehlerzustände.
Ein UI, das nur mit „John Doe“ und „Lorem ipsum“ funktioniert, ist noch nicht produktionsreif.
Fazit
ui.shadcn.com ist weniger eine klassische UI-Bibliothek als ein moderner Baukasten für eigene Komponentenarchitekturen.
Der große Reiz liegt in der Verbindung aus:
- hochwertigem Ausgangsdesign,
- zugänglichen Interaktions-Primitives,
- Tailwind-basierter Anpassbarkeit,
- lokalem Komponenten-Code,
- TypeScript-Unterstützung,
- flexibler Komposition,
- wachsendem Registry- und Block-Ökosystem.
shadcn/ui eignet sich besonders für Teams, die nicht nur schnell Oberflächen bauen, sondern langfristig ein kontrollierbares, markenfähiges und wartbares UI-System entwickeln möchten.
Die Kehrseite dieser Freiheit ist Verantwortung: Komponenten müssen bewusst gepflegt, aktualisiert, getestet und architektonisch eingeordnet werden. Wer diese Verantwortung akzeptiert, erhält mit shadcn/ui eine außergewöhnlich starke Grundlage für moderne React-Anwendungen.