# Tailwind v4 Migration für shadcn: Schritt für Schritt

> Die Tailwind v4 Migration für shadcn in der richtigen Reihenfolge: Codemod, tailwind.config nach @theme inline, hsl zu oklch, Border, Ring und tw-animate-css.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 6. Nov. 2026
- Kategorie: [Next.js und Tailwind CSS](https://wingo-ui.com/de/blog/category/nextjs-tailwind)
- Lesezeit: 11 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/shadcn-tailwind-v4-migration
- Englische Fassung: https://wingo-ui.com/blog/shadcn-tailwind-v4-migration

## Kurz gesagt

Migrier ein shadcn-Projekt auf einem eigenen Branch zu Tailwind v4: Führ npx @tailwindcss/upgrade aus, hol :root und .dark aus @layer base, setz jeden Wert in hsl(), bilde die Variablen in @theme inline ab, lösch dann tailwind.config.js und lass das Feld config in components.json leer. Tausch tailwindcss-animate gegen tw-animate-css und prüf von Hand, was der Codemod nicht sieht: Border- und Ring-Klassen ohne Farbe, Klassennamen, die erst zur Laufzeit entstehen, Chart-Farben und die Keyframes des Accordions.

Du hast eine funktionierende shadcn/ui-App auf Tailwind v3, und neue shadcn-Komponenten wie die meisten aktuellen Tutorials gehen inzwischen von Tailwind v4 aus. Die Tailwind v4 Migration eines shadcn-Projekts läuft größtenteils mechanisch ab, aber die Teile, die es nicht sind, scheitern lautlos: Borders werden schwarz, Fokusringe dünner, Accordions animieren nicht mehr, und eine Farbe aus `tailwind.config.js` tut einfach gar nichts. Dieser Guide zeigt die Reihenfolge, der wir in einem echten Projekt folgen würden, mit dem CSS vor und nach jedem Schritt und einer Liste der Komponenten, die du von Hand nachbessern musst. Wir bauen Wingo UI, eine Komponentenbibliothek für React 19 und Tailwind v4. Fakten von außen verlinken deshalb auf ihre Quellen, geprüft am 6. November 2026.

## Solltest du ein shadcn-Projekt jetzt auf Tailwind v4 migrieren?

Ja, wenn deine Nutzer aktuelle Browser haben. Tailwind v4 braucht laut [Tailwind Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide) mindestens Safari 16.4, Chrome 111 oder Firefox 128. Musst du ältere Browser unterstützen, bleib bei v3.4. Das Upgrade-Tool braucht außerdem Node.js 20 oder neuer.

Eine Deadline gibt es nicht. Die [shadcn-Seite zu Tailwind v4](https://ui.shadcn.com/docs/tailwind-v4) nennt die Umstellung nicht breaking: Bestehende Apps mit v3 und React 18 laufen weiter, und Komponenten, die du hinzufügst, bleiben bei v3, bis du upgradest. Der Preis fürs Warten: Jede neue Komponente und jedes Beispiel, das du kopierst, ist für v4 geschrieben.

Mach die Arbeit auf einem eigenen Branch, ohne Feature-Änderungen dazwischen, damit der Diff nur die Migration zeigt.

## Welche Tailwind v4 Breaking Changes treffen shadcn?

Der [Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide) listet rund zwanzig. Diese hier begegnen dir in einem shadcn-Projekt:

| Änderung | v3 | v4 | Wo es auffällt |
| --- | --- | --- | --- |
| Konfiguration | `tailwind.config.js` | CSS: `@theme`, `@plugin`, `@utility` | jedes Farb- und Radius-Token |
| Einstiegspunkt | `@tailwind base; components; utilities` | `@import "tailwindcss";` | `globals.css` |
| PostCSS-Plugin | `tailwindcss` + `autoprefixer` | `@tailwindcss/postcss` | `postcss.config.mjs` |
| Standardfarbe für Borders | `gray-200` | `currentColor` | jede `border`-Klasse ohne Farbe |
| `ring` ohne Wert | 3px, `blue-500` | 1px, `currentColor` | eigene Fokus-Styles |
| `outline-none` | unsichtbare Outline | `outline-style: none`; das alte Verhalten heißt `outline-hidden` | Buttons, Inputs, Trigger |
| Umbenannte Skalen | `shadow-sm`, `rounded-sm`, `blur-sm` | `shadow-xs`, `rounded-xs`, `blur-xs` | Cards, Popover, Inputs |
| Kurzschreibweise für CSS-Variablen | `w-[--sidebar-width]` | `w-(--sidebar-width)` | Sidebar, eigene Breiten |
| `hover:` | immer | nur auf Geräten, die hovern können | alles, was sich auf hängenden Hover am Smartphone verlassen hat |
| Cursor auf Buttons | `pointer` | `default` | jeder `<button>` |
| Eigene Utilities | `@layer utilities` | `@utility name { ... }` | deine eigenen Helfer |

Die Hover-Änderung ist gut fürs Smartphone: Nach einem Tipp bleibt ein Button nicht mehr in seiner Hover-Farbe hängen. Die Cursor-Änderung fällt den meisten als Erstes auf.

## Schritt 1: Wie führst du den Upgrade-Codemod aus?

Committe alles und starte dann das offizielle Tool im Projektverzeichnis:

```bash
git switch -c chore/tailwind-v4
npx @tailwindcss/upgrade
```

Das Tool aktualisiert `package.json`, ersetzt die drei `@tailwind`-Direktiven durch `@import "tailwindcss";`, stellt PostCSS auf `@tailwindcss/postcss` um, wandelt deine JavaScript-Config in CSS um und benennt Utilities in deinen Quelldateien um (`shadow-sm` zu `shadow-xs`, `outline-none` zu `outline-hidden`, `w-[--x]` zu `w-(--x)`). Die shadcn-Seite zu Tailwind v4 zeigt den Befehl noch mit `@next`, ein Überbleibsel aus der Beta von v4; der aktuelle Tailwind Guide lässt das Tag weg.

Zwei Grenzen sind wichtig. Das Tool kann nur Klassennamen umschreiben, die es als vollständige Strings lesen kann; alles, was erst zur Laufzeit entsteht (`` `bg-${tone}-500` ``), bleibt unverändert. Und es bildet deine Tokens mit `hsl(var(--x))`-Wrappern in `@theme` ab, was funktioniert, aber umständlich ist. Schritt 2 räumt das auf. Bricht das Tool mit „Could not load the configuration file“ ab (der Fehler wurde in der [shadcn-Diskussion zum Upgrade](https://github.com/shadcn-ui/ui/discussions/2996) gemeldet), prüf mit `node -e "require('./tailwind.config.js')"`, ob die Config für sich allein lädt. Behebe, was dabei ausgegeben wird, bevor du das Tool erneut startest.

Starte danach den Dev-Server und sieh dir die App an, bevor du irgendetwas anderes änderst.

## Schritt 2: Wie ziehst du tailwind.config nach @theme um?

Das ist der Kern, wenn du Tailwind v3 auf v4 upgraden willst. Ein shadcn-Projekt mit v3 hält die Rohwerte in `globals.css` und die Zuordnung zu Utilities in `tailwind.config.js`:

```js
// tailwind.config.js (v3)
module.exports = {
  darkMode: ["class"],
  theme: {
    extend: {
      colors: {
        border: "hsl(var(--border))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
};
```

In v4 gibt es keine separate Tailwind v4 Config-Datei mehr: Beide Hälften wandern ins CSS. Die shadcn-Doku nennt vier Änderungen zusätzlich zur Ausgabe des Codemods: `:root` und `.dark` aus `@layer base` herausholen, jeden Wert in `hsl()` setzen, `@theme` zu `@theme inline` ändern und die `hsl()`-Wrapper darin entfernen. Das Ergebnis:

```css
/* app/globals.css (v4) */
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));

:root {
  --radius: 0.5rem;
  --background: hsl(0 0% 100%);
  --foreground: hsl(222.2 84% 4.9%);
  --primary: hsl(222.2 47.4% 11.2%);
  --primary-foreground: hsl(210 40% 98%);
  --border: hsl(214.3 31.8% 91.4%);
  --ring: hsl(222.2 84% 4.9%);
}

.dark {
  --background: hsl(222.2 84% 4.9%);
  --foreground: hsl(210 40% 98%);
  --primary: hsl(210 40% 98%);
  --primary-foreground: hsl(222.2 47.4% 11.2%);
  --border: hsl(217.2 32.6% 17.5%);
  --ring: hsl(212.7 26.8% 83.9%);
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-border: var(--border);
  --color-ring: var(--ring);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
}

@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
}
```

Warum `inline` wichtig ist: Mit einfachem `@theme` wird `bg-background` zu `var(--color-background)` kompiliert, und diese Variable wird dort aufgelöst, wo sie definiert ist, auf `:root`. Eine `.dark`-Klasse unterhalb der Wurzel oder ein Theme, das nur für einen Abschnitt gilt, ändert sie nie. Mit `@theme inline` schreibt Tailwind `var(--background)` direkt in die Utility, der Wert wird also auf dem Element aufgelöst, das sie nutzt. In der shadcn-Diskussion zum Upgrade berichtete jemand am 28. Dezember 2024, dass der Dark Mode erst nach dem Wechsel auf `@theme inline` funktionierte. Der Guide zum [Tailwind v4 Dark Mode](https://wingo-ui.com/de/blog/tailwind-v4-dark-mode) behandelt die Klassen-Variante und next-themes im Detail.

Aus `darkMode: ["class"]` wird die `@custom-variant`-Zeile. Die Regel `* { @apply border-border; }` kompiliert erst, wenn `--color-border` in `@theme` existiert; „Cannot apply unknown utility class: border-border“ heißt, dass die Zuordnung fehlt oder noch eine alte Config geladen wird.

Sieht die Seite richtig aus, lösch `tailwind.config.js` und die `@config`-Zeile, die der Codemod eingefügt hat, und setz den Config-Pfad in `components.json` auf leer, wie es die [Doku zu components.json](https://ui.shadcn.com/docs/components-json) für v4 vorgibt:

```json
{
  "tailwind": {
    "config": "",
    "css": "app/globals.css",
    "baseColor": "slate",
    "cssVariables": true
  }
}
```

## Schritt 3: Solltest du hsl-Tokens in oklch umwandeln?

Nur wenn du willst. Sobald jede Variable eine vollständige Farbe enthält, funktioniert `hsl()` in v4 problemlos, und das Format ändert nichts am Kontrast. Die aktuelle Palette von shadcn ist oklch (das Neutral-Theme nutzt laut [Theming-Doku](https://ui.shadcn.com/docs/theming) `--background: oklch(1 0 0)` und `--foreground: oklch(0.145 0 0)`), und die dunklen Farben wurden am 12. März 2025 für bessere Barrierefreiheit überarbeitet. Willst du diese Werte, kopier sie von der Theming-Seite, statt deine eigenen umzurechnen, und lass deine Markenfarbe, wie sie ist.

Zwei Dinge musst du jetzt ändern, weil die Variablen vollständige Farben enthalten:

```ts
// Chart-Config: die Variable ist schon eine Farbe
const chartConfig = {
  desktop: { label: "Desktop", color: "var(--chart-1)" }, // vorher "hsl(var(--chart-1))"
  mobile: { label: "Mobil", color: "var(--chart-2)" },
};
```

Such außerdem in deinem Code nach `hsl(var(--` in Inline-Styles, SVG-Fills und `color-mix()`-Aufrufen. Jede dieser Stellen packt jetzt eine Farbe in ein zweites `hsl()` und rendert gar nichts. Ein shadcn Tailwind v4 Theme, dessen Tokens vollständige Farben sind, lässt sich auch leichter erweitern: `color-mix(in oklab, var(--primary) 10%, transparent)` funktioniert überall. Unser Guide zu [Tailwind v4 Design Tokens](https://wingo-ui.com/de/blog/tailwind-v4-design-tokens) geht weiter, mit Flächen, Status-Tones und einem Kontrast-Skript.

## Schritt 4: Wie reparierst du Borders und Fokusringe?

Such nach jedem `border`, `border-t`, `divide-y` und `ring` ohne Farbe. Die Basisregel aus Schritt 2 repariert Borders global, deshalb sehen die meisten shadcn-Komponenten nach dem Upgrade richtig aus. Alles, was außerhalb der Reichweite deines Stylesheets gerendert wird (ein Portal in die Wurzel einer Fremdbibliothek, ein iframe), zeichnet weiter Borders in `currentColor`.

Bei Ringen ist es subtiler. Die Standardkomponenten von shadcn v3 nutzen `ring-2`, das seine Breite behält, aber in eigenem Code schrumpft ein `ring` ohne Wert von 3px auf 1px, und ein 1px-Ring taugt oft nicht als Fokusindikator. Schreib Breite und Farbe explizit aus:

```tsx
// vorher: 3px blau in v3, 1px currentColor in v4
<button className="focus-visible:ring">Speichern</button>

// nachher: in beiden Versionen explizit
<button className="outline-hidden focus-visible:ring-[3px] focus-visible:ring-ring/50">Speichern</button>
```

Willst du den Pointer-Cursor auf allen Buttons zurück, füg das Snippet aus dem Upgrade Guide ein:

```css
@layer base {
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}
```

Geh danach jede Seite mit der Tastatur durch, in beiden Themes. Dieser eine Durchgang findet die meisten Regressionen bei Ringen und Outlines.

## Schritt 5: Was ersetzt tailwindcss-animate?

`tw-animate-css`. shadcn hat `tailwindcss-animate` am 19. März 2025 als veraltet markiert, und neue Projekte bekommen den Ersatz standardmäßig:

```bash
npm uninstall tailwindcss-animate
npm install -D tw-animate-css
```

Entferne `@plugin "tailwindcss-animate";` aus `globals.css` und füg `@import "tw-animate-css";` nach dem Tailwind-Import ein. Die Klassen, die deine Dialoge, Popover und Dropdowns nutzen (`animate-in`, `fade-in-0`, `zoom-in-95`, `slide-in-from-top-2`), funktionieren weiter, und das Paket bringt `animate-accordion-down` und `animate-accordion-up` mit, die Keyframes aus `tailwind.config.js` können also weg. Laut [README](https://github.com/Wombosvideo/tw-animate-css) ist es kein hundertprozentig kompatibler Drop-in-Ersatz, klick also jede animierte Komponente einmal durch.

Eine andere Möglichkeit: in JavaScript animieren. Unsere Komponenten nutzen `motion`-Springs statt Keyframes. Beim [Accordion](https://wingo-ui.com/components/accordion) federt die Höhe per Spring auf, und die Antwort wird eingeblendet; bei reduzierter Bewegung entfällt die Höhenanimation, und die Antwort wird nur eingeblendet. Ein Animations-Plugin, das du migrieren müsstest, gibt es gar nicht.

> Live-Demo (Accordion): Öffne eine Zeile, dann eine andere: Die Höhe federt auf, und die Antwort erscheint, bevor die Höhe zur Ruhe kommt. Schalte in den Systemeinstellungen reduzierte Bewegung ein, dann wird die Antwort einfach an Ort und Stelle eingeblendet. Probier sie unter [Accordion](https://wingo-ui.com/components/accordion) aus und installier sie mit `npx wingo-ui@latest add accordion`.

## Welche shadcn-Komponenten musst du von Hand nachbessern?

Bei einer shadcn Tailwind v4 Migration erledigt der Codemod die meisten Klassen-Strings. An diesen Stellen verpasst er etwas, oder die neuen Defaults ändern den Look:

- **Sidebar**: Sie setzt ihre Größe mit Klassen wie `w-[--sidebar-width]`, die v4 als `w-(--sidebar-width)` schreibt. Prüf, ob der Codemod jede davon erwischt hat und ob die Sidebar noch in voller Breite aufgeht. Jemand, dessen Sidebar nach dem Upgrade kaputt war, hat das am 3. Februar 2025 gelöst, indem er `sidebar.tsx` und `globals.css` aus der Tailwind-v4-Beispiel-App von shadcn übernommen hat.
- **Radius-Klassen**: Der Codemod benennt `rounded-sm` in `rounded-xs` und `rounded` in `rounded-sm` um. Dein Theme bildet `--radius-sm` selbst ab, die Umbenennung kann also den Look ändern: `rounded-sm` bedeutete vorher `--radius` minus 4px, und `rounded-xs` fällt auf Tailwinds Default von 2px zurück. Vergleich ein paar Inputs und Badges mit dem v3-Build und behalte die Klasse, die den Radius ergibt, den du hattest.
- **Accordion und Collapsible**: Sie verlieren ihre Animation, wenn du die Keyframes aus der Config entfernt hast, bevor `tw-animate-css` drin war.
- **Chart**: `hsl(var(--chart-n))` in `chartConfig`, siehe Schritt 3.
- **Toast**: zugunsten von Sonner als veraltet markiert. Dein bestehender Toast läuft weiter, aber shadcn verweist neue Projekte inzwischen auf `sonner`.
- **Alles mit `cva`-Varianten aus Template-Strings**: Die kann das Tool nicht lesen. Such mit grep nach `` `${ `` in `className`.
- **Komponenten, die du angepasst hast**: `npx shadcn@latest add --all --overwrite` überschreibt jede Datei mit der v4-Version. Committe vorher und spiel deine Änderungen danach aus dem Diff wieder ein. Unser Artikel zum [Updaten von shadcn-Komponenten, ohne Anpassungen zu verlieren](https://wingo-ui.com/de/blog/update-shadcn-components-without-losing-edits), erklärt, warum ein Three-Way-Merge dir diesen Schritt erspart.

Die restlichen v4-Änderungen von shadcn sind optional: `size-4` statt `w-4 h-4`, `data-slot` auf jedem Teil und normale Funktionen statt `forwardRef` (React 19 übergibt `ref` als Prop; siehe unsere [Migration von forwardRef in React 19](https://wingo-ui.com/de/blog/react-19-forwardref-ref-as-prop)).

## Wie sieht eine Komponente aus, die für Tailwind v4 geschrieben ist?

Sie färbt über CSS-Variablen, nutzt für Touch und Fokus v4-Varianten statt JavaScript und braucht keine Config-Datei. Unser [Button](https://wingo-ui.com/components/button) ist ein gutes Beispiel: Die Varianten färben über CSS-Variablen mit der neuen Kurzschreibweise (`bg-(--tone)`, `text-(--tone-foreground)`), der Fokus nutzt `outline-hidden` plus eine 2px breite `outline-ring`, und die Variante `pointer-coarse:` vergrößert die Standardgröße auf Touchscreens auf 44px, ganz ohne JavaScript. Die `--tone-*`-Variablen kommen aus [Tones](https://wingo-ui.com/components/tones), also ändern `tone="success"` oder `color="#0EA5E9"` jede Variante ohne neue Klassen:

```tsx
import { Button } from "@/components/ui/button";

export function SaveBar() {
  return (
    <div className="flex gap-2">
      <Button variant="outline">Abbrechen</Button>
      <Button tone="brand" loading loadingText="Wird gespeichert">
        Änderungen speichern
      </Button>
    </div>
  );
}
```

> Live-Demo (Button): Spring mit Tab zu einem Button, um die 2px breite Fokus-Outline zu sehen, drück ihn, um die Spring zu spüren, und wechsel dann das Theme der Seite: Füllungen, Tints und Outline kommen alle aus den Tokens. Probier sie unter [Button](https://wingo-ui.com/components/button) aus und installier sie mit `npx wingo-ui@latest add button`.

App-weite Defaults laufen über [UIProvider](https://wingo-ui.com/components/ui-config). Eine migrierte App kann `radius` oder `size` also einmal setzen, statt jede Datei anzufassen:

```tsx
"use client";

import type { ReactNode } from "react";
import { UIProvider } from "@/lib/ui-config";

export function Providers({ children }: { children: ReactNode }) {
  return (
    <UIProvider defaults={{ button: { radius: "full" }, card: { variant: "outline" } }}>
      {children}
    </UIProvider>
  );
}
```

Wenn du unsere Komponenten ins migrierte Projekt holst, führ `npx wingo-ui@latest init` nach der Migration aus, nicht davor. Es liest den Pfad zum Stylesheet aus `components.json`, warnt, wenn diese Datei noch ein v3-Stylesheet ohne `@import "tailwindcss"` ist, und ergänzt nur die Tokens, die fehlen: Werte, die dein shadcn-Theme schon definiert, bleiben, wie sie sind. Danach holt `npx wingo-ui@latest add button card` den Quellcode von [Card](https://wingo-ui.com/components/card) und Button in dein Projekt. Weitere Guides zu diesem Stack findest du in [Next.js und Tailwind CSS](https://wingo-ui.com/de/blog/category/nextjs-tailwind).

## Wie prüfst du, ob die Migration geklappt hat?

Geh diese Liste durch, bevor du mergst:

1. `npm run build` läuft durch, und der Dev-Server zeigt keine Fehler wegen unbekannter Utilities („unknown utility“).
2. Jede Seite in Light und Dark: keine schwarzen Borders, keine fehlenden Hintergründe.
3. Tastatur-Durchgang: Jedes Control zeigt einen sichtbaren Fokusring.
4. Öffne jeden Dialog, jedes Sheet, Popover, Dropdown und Accordion: Alle animieren noch.
5. Charts zeigen ihre Farben.
6. Auf dem Smartphone: Buttons bleiben nach einem Tipp nicht eingefärbt, und die Sidebar geht in voller Breite auf.
7. `git grep -n "hsl(var(--"` und `git grep -n "tailwind.config"` finden nichts mehr, was du noch brauchst.

## Wie geht es weiter?

Lass den Codemod noch heute auf einem Branch laufen und behebe, was die Checkliste findet; bei einer typischen shadcn-App bleiben für die Handarbeit ein paar kleine Commits. Willst du Komponenten, die von Anfang an für Tailwind v4 geschrieben wurden, mit fertigen Tokens, Fokusringen und Touch-Größen, hol dir Button, Card und Accordion mit einem kostenlosen Konto (nur E-Mail, keine Karte): Sie gehören zu den 75 kostenlosen von insgesamt 357 Items im Katalog, und die [Preisseite](https://wingo-ui.com/de/pricing) zeigt, was Pro zusätzlich bietet.

## Komponenten in diesem Artikel

- [Button](https://wingo-ui.com/components/button) (Free): The React button component every screen starts with: five variants, six tones, all sizes, and a loading state that never jumps. Installation: `npx wingo-ui@latest add button`
- [UIProvider](https://wingo-ui.com/components/ui-config) (Free): A React config provider for Wingo UI: app-wide default props for every component, the Intl locale and a reduced-motion policy. Installation: `npx wingo-ui@latest add ui-config`
- [Tones](https://wingo-ui.com/components/tones) (Free): One way to color a React component: a tone or any CSS color becomes five CSS variables every variant paints with. Installation: `npx wingo-ui@latest add tones`
- [Card](https://wingo-ui.com/components/card) (Free): A React card component for listings, stats, settings and plans: media, header, body and footer parts, and a lift-and-press mode. Installation: `npx wingo-ui@latest add card`
- [Accordion](https://wingo-ui.com/components/accordion) (Free): A React accordion component for FAQs, settings sections and order details, with four variants, icons, descriptions and one or many open. Installation: `npx wingo-ui@latest add accordion`

## Häufige Fragen

### Unterstützt shadcn/ui Tailwind v4?

Ja. Die shadcn CLI richtet neue Projekte mit Tailwind v4 und React 19 ein, und jede Komponente hat data-slot-Attribute und oklch-Farben bekommen. Bestehende Projekte mit Tailwind v3 laufen weiter, und die shadcn-Doku nennt das Upgrade nicht breaking.

### Brauche ich mit Tailwind v4 noch eine tailwind.config-Datei?

Nein. Tailwind v4 liest seine Konfiguration aus dem CSS: Theme-Werte stehen in @theme, Plugins in @plugin, eigene Utilities in @utility. Eine JavaScript-Config funktioniert noch, wenn du sie mit @config lädst, sie wird aber nicht mehr automatisch erkannt, und die components.json von shadcn erwartet in v4 ein leeres Feld tailwind.config.

### Warum sind meine Borders nach dem Upgrade auf Tailwind v4 schwarz?

Tailwind v4 hat die Standardfarbe für Borders von gray-200 auf currentColor geändert, eine Border-Klasse ohne Farbe übernimmt also die Textfarbe. shadcn-Projekte lösen das mit einer Basisregel, * { @apply border-border; }, die nur funktioniert, wenn --color-border in @theme inline abgebildet ist.

### Was ersetzt tailwindcss-animate in Tailwind v4?

tw-animate-css, das shadcn am 19. März 2025 übernommen hat. Installier es als Dev-Dependency, entferne @plugin "tailwindcss-animate" und füg @import "tw-animate-css" nach @import "tailwindcss" ein. Es deckt animate-in, fade, zoom, slide und die Keyframes für Accordion und Collapsible ab, laut README ist es aber kein hundertprozentiger Drop-in-Ersatz.

### Muss ich meine shadcn-Farben von hsl auf oklch umstellen?

Nein. hsl()-Werte funktionieren in Tailwind v4, solange jede Variable eine vollständige Farbe enthält. Stell nur auf oklch um, wenn du die aktuelle shadcn-Palette willst oder die Helligkeit leichter anpassen möchtest, und lass nach jeder geänderten Farbe einen Kontrast-Check laufen.

---

Quelle: https://wingo-ui.com/de/blog/shadcn-tailwind-v4-migration
