shadcn Vite Setup mit Tailwind CSS v4 und React 19

Die meisten Anleitungen zum shadcn Vite Setup wurden für Vite 5 und TypeScript 5 geschrieben, und zwei ihrer Schritte funktionieren heute nicht mehr. Das aktuelle Vite-Template bringt TypeScript 6 mit, das baseUrl ablehnt. Außerdem prüft es deinen Code über tsconfig.app.json, ein Alias nur in tsconfig.json kommt dort also nie an. Dieser Guide richtet ein Projekt mit Vite, React 19 und Tailwind CSS v4 ein, das Komponenten im shadcn-Stil aufnimmt. Danach installierst du sie mit der Wingo UI CLI oder der shadcn CLI, jeweils mit ihren Vor- und Nachteilen.
Alles hier haben wir am 13. Oktober 2026 ausgeführt, mit create-vite 9.2.1 (Vite 8.3.4, React 19.3.0, TypeScript 6.0.3), Tailwind CSS 4.3.3, der wingo-ui CLI 1.0.3, der shadcn CLI 4.21.4 und next-themes 0.4.6. Die Next.js-Variante dieses Setups findest du im Guide zum Next.js Component Library Setup.
Was braucht ein Vite-Projekt für Komponenten im shadcn-Stil?
Komponenten, deren Quellcode dir gehört, sind einfache .tsx-Dateien. Sie importieren sich gegenseitig über einen Alias, stylen sich mit Tailwind-Utilities und lesen Farben aus CSS-Variablen. Ein Vite Tailwind v4 React Projekt braucht dafür fünf Dinge:
Wie läuft ein shadcn Vite Setup Schritt für Schritt?
1. Projekt anlegen und Tailwind installieren
In create-vite 9.2.1 steht @types/node bereits im Template. Eine zweite Installation schadet nicht, und ältere Templates brauchen das Paket für path in der Config.
Ersetz den gesamten Inhalt von src/index.css durch eine Zeile und lösch src/App.css samt Import in src/App.tsx. Das Starter-CSS stylt #root, h1 und body und würde mit den Komponenten kollidieren.
2. Plugin und Vite Path Alias ergänzen
Dieser Vite Path Alias gilt nur für den Bundler. TypeScript liest vite.config.ts nicht, es braucht also eine eigene Kopie.
3. tsconfig.app.json paths setzen, ohne baseUrl
Die tsconfig.json des Templates hat "files": [] und zwei Referenzen. Dein src wird über tsconfig.app.json geprüft. Trag den Alias in beide Dateien ein:
Drei Details, jedes aus einem fehlgeschlagenen Durchlauf:
- Paths nur in
tsconfig.jsonreichen nicht. Wir habenwingo-ui initden Alias selbst eintragen lassen. Es schrieb ihn intsconfig.json, undtsc -bscheiterte danach mitCannot find module '@/components/ui/button', weiltsconfig.app.jsonihn nie gesehen hat. - Kein
baseUrlunter TypeScript 6. Mit"baseUrl": "."intsconfig.app.jsonbrachtsc -bmit Fehler TS5101 ab: Die Option ist veraltet und funktioniert ab TypeScript 7 nicht mehr.pathslöst ohne sie relativ zur Config-Datei auf. nodeintypesaufnehmen. Das Template beschränkt die globalen Typen aufvite/client. Manche Komponenten lesenprocess.env.NODE_ENV, um Warnungen in der Entwicklung auszugeben (Theme Toggle macht das), und ohne den Eintrag meldettscden FehlerCannot find name 'process'. Vite ersetzt den Ausdruck beim Build: In unserem Production-Bundle war keinprocess.envmehr übrig.
4. init ausführen
init erkannte vite, fand den Alias in tsconfig.app.json (die CLI folgt der references-Liste) und meldete alias @/* -> src/. Danach legte es src/lib/utils.ts mit cn an, installierte clsx und tailwind-merge, führte die Tokens in src/index.css zusammen, mit einem .dark-Block und @custom-variant dark (&:is(.dark *));, und schrieb wingo-ui.json.
Steht react-router oder @react-router/dev in package.json, speichert init als Framework react-router statt vite, weil es zuerst nach React Router sucht. Dateipfade und Befehle bleiben gleich.
5. Komponenten hinzufügen
Die kostenlosen Items installierst du ohne Account. Die Dateien landen in src/components/ui, src/hooks und src/lib, zusammen mit den npm-Paketen, die sie importieren. Gib der Seite ihre Farben in index.html, denn das Starter-CSS, das body gestylt hat, ist weg:
Dann nutzt du sie:
npm run build (das vorher tsc -b ausführt) lief mit dieser Datei durch. Button, Card und Dialog tragen "use client" ganz oben, für den Next.js App Router. Vite ignoriert die Direktive. Drück den Button unten, um seinen Ladezustand zu sehen.
$ npx wingo-ui@latest add buttonWie bekomme ich Dark Mode in Vite ohne Next.js?
Die Komponenten folgen einer .dark-Klasse am <html>-Element. Irgendetwas muss sie vor dem ersten Paint setzen, und irgendetwas muss sie ändern, wenn der Nutzer ein Theme wählt. Unser Guide zu Tailwind v4 Dark Mode erklärt die @custom-variant-Zeile, auf die sich die Komponenten verlassen.
Vor dem Paint: Ein Script in index.html, im <head>, liest die gespeicherte Wahl und die Systemeinstellung:
Beim Wechsel: next-themes. Trotz des Namens hängt Version 0.4.6 nur von React ab, und sie speichert die Wahl unter demselben Schlüssel theme, den das Script liest:
Wir haben den Production-Build mit Playwright in Chromium in beiden Farbschemata geladen. Bevorzugte das System Dark Mode, stand die Klasse dark schon am <html>, bevor React startete. Der Theme Toggle schaltete sie um, und localStorage behielt die Wahl. UIProvider ist optional: Er setzt app-weite Standardwerte für Komponenten und die Locale für Datums- und Zahlenformate.
Was in der Bibliothek nutzt next-themes? Stand 13. Oktober 2026 importiert nur theme-toggle.tsx das Paket, und die CLI installiert es mit diesem Item. Theme Toggle (Pro) akzeptiert auch value und onValueChange, falls du das Theme lieber in deinem eigenen State hältst. Dann setzt dein Code die Klasse. Drei Navigationskomponenten, Bounce Sidebar, Hook Sidebar und Gooey Nav, importieren next/link und brauchen deshalb Next.js. Alles andere läuft unverändert in Vite.
Kann ich in Vite stattdessen die shadcn CLI nutzen?
Ja, mit Grenzen, die du vorher kennen solltest. Wir haben npx shadcn@latest init -t vite -b radix -p nova in einem frischen Projekt nach Schritt 3 ausgeführt. Wähl Radix: Die Installations-Doku weist darauf hin, dass die Base-UI-Styles asChild umschreiben, und darauf verlassen sich diese Komponenten. Init 4.21.4 schrieb components.json, src/lib/utils.ts und eine eigene src/components/ui/button.tsx.
Kostenlose Wingo-UI-Items installierst du über ihre URL:
Die CLI fragte, ob sie utils.ts und danach button.tsx überschreiben soll. Bei utils.ts antwortest du mit Nein: Die shadcn-Version exportiert cn aus dem Paket cn weiter, einem direkten Ersatz für clsx plus tailwind-merge, und unsere Dateien brauchen nur einen cn-Export. Und hier liegt der Haken. Behältst du den Button von shadcn, besteht unser Dialog den Type Check nicht mehr, weil er Props wie radius übergibt, die der shadcn-Button nicht kennt. Überschreibst du ihn, brechen stattdessen shadcn-Komponenten, die dessen API brauchen: Der Calendar von shadcn importiert buttonVariants, und unser Button exportiert das nicht. Die shadcn CLI hat außerdem unsere Tokens nicht in src/index.css eingetragen, und sie speichert keine Versionen. wingo-ui update kann spätere Releases deshalb nicht in diese Dateien mergen.
Für Pro-Items trägst du laut Doku den Namespace @wingo-ui in components.json ein, mit deinem Key in einer Umgebungsvariable, und führst dann npx shadcn@latest add @wingo-ui/calendar aus. Diesen Weg haben wir für diesen Artikel nicht mit einem Key getestet.
Das Setup, das funktioniert hat: ein Ordner pro Bibliothek
Im selben shadcn-Projekt haben wir npx wingo-ui@latest init ausgeführt. Es ergänzte nur die 43 Token-Namen, die shadcn nicht definiert hatte. Dann haben wir "ui" in wingo-ui.json auf "@/components/wingo" geändert und npx wingo-ui@latest add dialog ausgeführt. Unsere Dateien landeten in src/components/wingo, ihre Imports wurden passend umgeschrieben, die button.tsx von shadcn blieb unangetastet, und tsc -b lief durch. Die CLI-Doku beschreibt die übrigen Aliase.
Was prüfe ich, wenn etwas kaputtgeht?
Nächster Schritt
Führ npx wingo-ui@latest add button card dialog in deinem neuen Projekt aus und öffne die Installations-Doku für den manuellen Weg. Das Token-System hinter all dem erklärt der Pillar-Artikel zu Tailwind v4 Design Tokens. Weitere Setup-Guides findest du unter Next.js und Tailwind CSS, darunter das Next.js Component Library Setup, falls du das Projekt auf den App Router umstellst.
Häufige Fragen
Funktioniert shadcn mit Vite?
Ja. shadcn-Komponenten sind Quelldateien aus React und Tailwind ohne Abhängigkeit zu Next.js. Vite braucht das Plugin @tailwindcss/vite, einen @-Alias in vite.config.ts und passende paths in tsconfig.app.json.
Warum meldet tsc in Vite, dass es das Modul @/components/ui/button nicht findet?
Das Vite-Template prüft src über tsconfig.app.json, eine Referenz von tsconfig.json. Paths, die nur in tsconfig.json stehen, kommen dort nicht an. Trag denselben paths-Eintrag für den @-Alias mit Ziel ./src deshalb auch in tsconfig.app.json ein.
Soll ich baseUrl in tsconfig.app.json eintragen?
Nicht unter TypeScript 6, das das Vite-Template Stand Oktober 2026 installiert. tsc -b bricht dann mit Fehler TS5101 ab, weil baseUrl veraltet ist, und paths funktioniert auch ohne.
Kann ich next-themes in einer Vite-App nutzen?
Ja. next-themes 0.4.6 nennt nur react und react-dom als Peer Dependencies. Umschließ die App mit ThemeProvider und attribute="class" und ergänz ein kleines Script in index.html, damit die Klasse vor dem ersten Paint gesetzt ist.
Kann ich Wingo-UI-Komponenten in Vite mit der shadcn CLI installieren?
Kostenlose Items installierst du über ihre URL, zum Beispiel npx shadcn@latest add https://wingo-ui.com/r/dialog.json (opens in a new tab). Die shadcn CLI ergänzt aber keine Wingo-UI-Tokens und speichert keine Versionen, und eine button.tsx von shadcn kollidiert mit unserer. Der bequemere Weg ist deshalb die Wingo UI CLI mit eigenem Ordner.
- Vite
- shadcn/ui
- Setup
- Installation
- Tailwind CSS v4


