This document describes how shadcn/ui integrates with Tailwind CSS, supporting both version 3 and version 4. It covers the CSS variable mapping system, the plugin architecture used for file updates, and the transformation pipeline that adapts registry components to match user project configurations.
For information about the overall theming system and design tokens, see 4.6 CSS Variable and Theme Management For the broader component installation pipeline, see 3.4 Component Installation Pipeline
shadcn/ui supports both Tailwind CSS v3 and v4 through a unified CSS variable system. The CLI detects the Tailwind version in the user's project and applies appropriate transformations to ensure components work correctly regardless of the version.
| Aspect | Tailwind v3 | Tailwind v4 |
|---|---|---|
| Configuration | tailwind.config.js/ts | CSS-first (No config file) |
| Theme System | JavaScript theme object | @theme directive in CSS |
| Dark Mode | darkMode: "class" | @custom-variant dark or class-based |
| Color Space | HSL (Legacy) | OKLCH (Default for new projects) |
| Plugins | require() in config | @plugin or @import in CSS |
| Slots | Standard classes | data-slot attributes for styling |
Sources: apps/v4/content/docs/(root)/components-json.mdx51-61 packages/shadcn/src/utils/updaters/update-tailwind-config.ts52-55 apps/v4/content/docs/(root)/theming.mdx100-108
For Tailwind v3 projects, configuration like darkMode, plugins, and theme.extend are managed in the tailwind.config.ts file using ts-morph via the updateTailwindConfig utility packages/shadcn/src/utils/updaters/update-tailwind-config.ts32-71
Diagram: Tailwind v3 Config Transformation Flow
The transformTailwindConfig function uses ts-morph to find the configuration object by searching for the content property, ensuring it targets the correct export even in complex files packages/shadcn/src/utils/updaters/update-tailwind-config.ts82-92 It handles merging theme objects using deepmerge while preserving spread properties like ... packages/shadcn/src/utils/updaters/update-tailwind-config.ts208-222
The CLI automatically ensures darkMode: "class" (or ["class"]) is present in the configuration to support shadcn/ui's theme toggling packages/shadcn/src/utils/updaters/update-tailwind-config.ts102-109 If darkMode exists as a string, it converts it to an array and appends "class" packages/shadcn/src/utils/updaters/update-tailwind-config.ts160-163
Sources: packages/shadcn/src/utils/updaters/update-tailwind-config.ts73-122 packages/shadcn/src/utils/updaters/update-tailwind-config.ts136-153
Tailwind v4 shifts to a CSS-first configuration. The CLI detects v4 and skips tailwind.config.js updates entirely packages/shadcn/src/utils/updaters/update-tailwind-config.ts53-55 Instead, it focuses on injecting variables and @theme directives into the global CSS file.
@theme and @theme inline directives within the CSS file apps/v4/content/docs/(root)/theming.mdx100-108--radius token using calc() inside the @theme block apps/v4/content/docs/(root)/theming.mdx99-109tailwind.config path in components.json should be left blank for v4 projects apps/v4/content/docs/(root)/components-json.mdx51-54In v4, the mapping between raw CSS variables and Tailwind utility colors is handled via the @theme inline block. This allows the design system to bridge the gap between static CSS variables and Tailwind's dynamic utility classes packages/tests/fixtures/next-app-init/app/globals.css6-15
Sources: apps/v4/content/docs/(root)/theming.mdx12-35 packages/shadcn/src/utils/updaters/update-tailwind-config.ts53-55 packages/tests/fixtures/next-app-init/app/globals.css1-45
Dark mode is implemented using the dark class on the html or body element apps/v4/content/docs/(root)/theming.mdx37 In Tailwind v4, this is typically defined via @custom-variant dark (&:is(.dark *)) packages/tests/fixtures/next-app-init/app/globals.css4
For frameworks like TanStack Start, a ThemeProvider component is provided that injects a script via ScriptOnce to prevent FOUC (Flash of Unstyled Content) by running logic before React hydrates apps/v4/content/docs/dark-mode/tanstack-start.mdx10-14
Diagram: Dark Mode Theme Provider Flow (TanStack Start Example)
The getThemeScript function generates a raw string of JavaScript that checks localStorage and prefers-color-scheme to apply the correct class to the documentElement immediately apps/v4/content/docs/dark-mode/tanstack-start.mdx29-34
Sources: apps/v4/content/docs/dark-mode/tanstack-start.mdx10-54 packages/tests/fixtures/next-app-init/app/globals.css82-114
Registry items can define their own CSS variables which the CLI injects into the project's CSS file. This allows components to ship with required design tokens.
Components can define cssVars for both light and dark modes, as well as general theme overrides.
Diagram: Registry CSS Variable Injection
registryItemTailwindSchema defines how Tailwind-specific configuration (like plugins or theme extensions) is stored in the registry packages/shadcn/src/utils/updaters/update-tailwind-config.ts6-7registryItemCssVarsSchema handles the metadata for injecting CSS variables into the user's stylesheet packages/shadcn/src/utils/updaters/update-tailwind-config.ts5-6primary to CSS variables such as var(--primary) which are then defined in the CSS file apps/v4/content/docs/(root)/theming.mdx49-60Sources: packages/shadcn/src/utils/updaters/update-tailwind-config.ts1-25 apps/v4/content/docs/(root)/theming.mdx62-86
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.