Skip to content

Commit a3fe507

Browse files
feat(monorepo): use tailwindcss v4 in monorepo example (#6724)
* feat(monorepo): use tailwindcss v4 in monorepo example * feat(shadcn): add monorepo tailwind detection * feat: update default monorepo template * fix: minor fixes * chore(shadcn): changeset * docs(www): update monorepo docs * docs: updates --------- Co-authored-by: shadcn <m@shadcn.com>
1 parent 3baef99 commit a3fe507

File tree

19 files changed

+1285
-1601
lines changed

19 files changed

+1285
-1601
lines changed

.changeset/cold-impalas-call.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"shadcn": patch
3+
---
4+
5+
support for version detection in monorepo

apps/www/content/docs/components-json.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ See the <Link href="/docs/installation">installation section</Link> for how to s
5151

5252
### tailwind.config
5353

54-
Path to where your `tailwind.config.js` file is located.
54+
Path to where your `tailwind.config.js` file is located. **For Tailwind CSS v4, leave this blank.**
5555

5656
```json title="components.json"
5757
{

apps/www/content/docs/monorepo.mdx

+68-14
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,6 @@ title: Monorepo
33
description: Using shadcn/ui components and CLI in a monorepo.
44
---
55

6-
<Callout>
7-
**Note:** We're releasing monorepo support in the CLI as __experimental__.
8-
Help us improve it by testing it out and sending feedback. If you have any
9-
questions, please [reach out to
10-
us](https://github.com/shadcn-ui/ui/discussions).
11-
</Callout>
12-
136
Until now, using shadcn/ui in a monorepo was a bit of a pain. You could add
147
components using the CLI, but you had to manage where the components
158
were installed and manually fix import paths.
@@ -47,6 +40,8 @@ and [Turborepo](https://turbo.build/repo/docs) as the build system.
4740

4841
Everything is set up for you, so you can start adding components to your project.
4942

43+
Note: The monorepo uses React 19 and Tailwind CSS v4.
44+
5045
### Add components to your project
5146

5247
To add components to your project, run the `add` command **in the path of your app**.
@@ -118,7 +113,66 @@ turbo.json
118113

119114
2. The `components.json` file must properly define aliases for the workspace. This tells the CLI how to import components, hooks, utilities, etc.
120115

121-
```json title="apps/web/components.json"
116+
<Tabs defaultValue="v4">
117+
118+
<TabsList>
119+
<TabsTrigger value="v4">Tailwind CSS v4</TabsTrigger>
120+
<TabsTrigger value="v3">Tailwind CSS v3</TabsTrigger>
121+
</TabsList>
122+
123+
<TabsContent value="v4">
124+
125+
```json showLineNumbers title="apps/web/components.json"
126+
{
127+
"$schema": "https://ui.shadcn.com/schema.json",
128+
"style": "new-york",
129+
"rsc": true,
130+
"tsx": true,
131+
"tailwind": {
132+
"config": "",
133+
"css": "../../packages/ui/src/styles/globals.css",
134+
"baseColor": "zinc",
135+
"cssVariables": true
136+
},
137+
"iconLibrary": "lucide",
138+
"aliases": {
139+
"components": "@/components",
140+
"hooks": "@/hooks",
141+
"lib": "@/lib",
142+
"utils": "@workspace/ui/lib/utils",
143+
"ui": "@workspace/ui/components"
144+
}
145+
}
146+
```
147+
148+
```json showLineNumbers title="packages/ui/components.json"
149+
{
150+
"$schema": "https://ui.shadcn.com/schema.json",
151+
"style": "new-york",
152+
"rsc": true,
153+
"tsx": true,
154+
"tailwind": {
155+
"config": "",
156+
"css": "src/styles/globals.css",
157+
"baseColor": "zinc",
158+
"cssVariables": true
159+
},
160+
"iconLibrary": "lucide",
161+
"aliases": {
162+
"components": "@workspace/ui/components",
163+
"utils": "@workspace/ui/lib/utils",
164+
"hooks": "@workspace/ui/hooks",
165+
"lib": "@workspace/ui/lib",
166+
"ui": "@workspace/ui/components"
167+
}
168+
}
169+
```
170+
171+
</TabsContent>
172+
173+
<TabsContent value="v3">
174+
175+
```json showLineNumbers title="apps/web/components.json"
122176
{
123177
"$schema": "https://ui.shadcn.com/schema.json",
124178
"style": "new-york",
@@ -141,7 +195,7 @@ turbo.json
141195
}
142196
```
143197

144-
```json title="packages/ui/components.json"
198+
```json showLineNumbers title="packages/ui/components.json"
145199
{
146200
"$schema": "https://ui.shadcn.com/schema.json",
147201
"style": "new-york",
@@ -164,12 +218,12 @@ turbo.json
164218
}
165219
```
166220

167-
3. Ensure you have the same `style`, `iconLibrary` and `baseColor` in both `components.json` files.
221+
</TabsContent>
168222

169-
By following these requirements, the CLI will be able to install ui components, blocks, libs and hooks to the correct paths and handle imports for you.
223+
</Tabs>
170224

171-
## Help us improve monorepo support
225+
3. Ensure you have the same `style`, `iconLibrary` and `baseColor` in both `components.json` files.
172226

173-
We're releasing monorepo support in the CLI as **experimental**. Help us improve it by testing it out and sending feedback.
227+
4. **For Tailwind CSS v4, leave the `tailwind` config empty in the `components.json` file.**
174228

175-
If you have any questions, please reach out to us on [GitHub Discussions](https://github.com/shadcn-ui/ui/discussions).
229+
By following these requirements, the CLI will be able to install ui components, blocks, libs and hooks to the correct paths and handle imports for you.

packages/shadcn/src/utils/get-project-info.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,15 @@ export async function getProjectInfo(cwd: string): Promise<ProjectInfo | null> {
153153
export async function getTailwindVersion(
154154
cwd: string
155155
): Promise<ProjectInfo["tailwindVersion"]> {
156-
const packageInfo = getPackageInfo(cwd)
156+
const [packageInfo, config] = await Promise.all([
157+
getPackageInfo(cwd),
158+
getConfig(cwd),
159+
])
160+
161+
// If the config file is empty, we can assume that it's a v4 project.
162+
if (config?.tailwind?.config === "") {
163+
return "v4"
164+
}
157165

158166
if (
159167
!packageInfo?.dependencies?.tailwindcss &&

packages/shadcn/src/utils/transformers/transform-import.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ export const transformImport: Transformer = async ({
2121
importDeclaration.setModuleSpecifier(moduleSpecifier)
2222

2323
// Replace `import { cn } from "@/lib/utils"`
24-
if (utilsImport === moduleSpecifier) {
24+
if (utilsImport === moduleSpecifier || moduleSpecifier === "@/lib/utils") {
2525
const namedImports = importDeclaration.getNamedImports()
2626
const cnImport = namedImports.find((i) => i.getName() === "cn")
2727
if (cnImport) {
2828
importDeclaration.setModuleSpecifier(
29-
moduleSpecifier.replace(utilsImport, config.aliases.utils)
29+
utilsImport === moduleSpecifier
30+
? moduleSpecifier.replace(utilsImport, config.aliases.utils)
31+
: config.aliases.utils
3032
)
3133
}
3234
}

templates/monorepo-next/apps/web/components.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"rsc": true,
55
"tsx": true,
66
"tailwind": {
7-
"config": "../../packages/ui/tailwind.config.ts",
7+
"config": "",
88
"css": "../../packages/ui/src/styles/globals.css",
9-
"baseColor": "zinc",
9+
"baseColor": "neutral",
1010
"cssVariables": true
1111
},
1212
"iconLibrary": "lucide",

templates/monorepo-next/apps/web/package.json

+9-9
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,24 @@
77
"dev": "next dev --turbopack",
88
"build": "next build",
99
"start": "next start",
10-
"lint": "next lint"
10+
"lint": "next lint",
11+
"lint:fix": "next lint --fix",
12+
"typecheck": "tsc --noEmit"
1113
},
1214
"dependencies": {
1315
"@workspace/ui": "workspace:*",
14-
"lucide-react": "0.456.0",
15-
"next-themes": "^0.4.3",
16-
"next": "^15.1.0",
16+
"lucide-react": "^0.475.0",
17+
"next": "^15.2.0",
18+
"next-themes": "^0.4.4",
1719
"react": "^19.0.0",
1820
"react-dom": "^19.0.0"
1921
},
2022
"devDependencies": {
2123
"@types/node": "^20",
22-
"@types/react": "18.3.0",
23-
"@types/react-dom": "18.3.1",
24+
"@types/react": "^19",
25+
"@types/react-dom": "^19",
2426
"@workspace/eslint-config": "workspace:^",
2527
"@workspace/typescript-config": "workspace:*",
26-
"postcss": "^8",
27-
"tailwindcss": "^3.4.1",
28-
"typescript": "^5"
28+
"typescript": "^5.7.3"
2929
}
3030
}

templates/monorepo-next/apps/web/tailwind.config.ts

-1
This file was deleted.

templates/monorepo-next/apps/web/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"include": [
1616
"next-env.d.ts",
17-
"next.config.mjs",
17+
"next.config.ts",
1818
"**/*.ts",
1919
"**/*.tsx",
2020
".next/types/**/*.ts"

templates/monorepo-next/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
"devDependencies": {
1212
"@workspace/eslint-config": "workspace:*",
1313
"@workspace/typescript-config": "workspace:*",
14-
"prettier": "^3.2.5",
15-
"turbo": "^2.3.0",
16-
"typescript": "5.5.4"
14+
"prettier": "^3.5.1",
15+
"turbo": "^2.4.2",
16+
"typescript": "5.7.3"
1717
},
18-
"packageManager": "pnpm@9.12.3",
18+
"packageManager": "pnpm@10.4.1",
1919
"engines": {
2020
"node": ">=20"
2121
}

templates/monorepo-next/packages/eslint-config/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
"./react-internal": "./react-internal.js"
1010
},
1111
"devDependencies": {
12-
"@next/eslint-plugin-next": "^15.1.0",
13-
"@typescript-eslint/eslint-plugin": "^8.15.0",
14-
"@typescript-eslint/parser": "^8.15.0",
15-
"eslint": "^9.15.0",
12+
"@next/eslint-plugin-next": "^15.1.7",
13+
"@typescript-eslint/eslint-plugin": "^8.24.1",
14+
"@typescript-eslint/parser": "^8.24.1",
15+
"eslint": "^9.20.1",
1616
"eslint-config-prettier": "^9.1.0",
1717
"eslint-plugin-only-warn": "^1.1.0",
18-
"eslint-plugin-react": "^7.37.2",
19-
"eslint-plugin-react-hooks": "^5.0.0",
20-
"eslint-plugin-turbo": "^2.3.0",
21-
"globals": "^15.12.0",
22-
"typescript": "^5.3.3",
23-
"typescript-eslint": "^8.15.0"
18+
"eslint-plugin-react": "^7.37.4",
19+
"eslint-plugin-react-hooks": "^5.1.0",
20+
"eslint-plugin-turbo": "^2.4.2",
21+
"globals": "^15.15.0",
22+
"typescript": "^5.7.3",
23+
"typescript-eslint": "^8.24.1"
2424
}
2525
}

templates/monorepo-next/packages/ui/components.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"rsc": true,
55
"tsx": true,
66
"tailwind": {
7-
"config": "tailwind.config.ts",
7+
"config": "",
88
"css": "src/styles/globals.css",
9-
"baseColor": "zinc",
9+
"baseColor": "neutral",
1010
"cssVariables": true
1111
},
1212
"iconLibrary": "lucide",

templates/monorepo-next/packages/ui/package.json

+13-16
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,31 @@
77
"lint": "eslint . --max-warnings 0"
88
},
99
"dependencies": {
10-
"@radix-ui/react-slot": "^1.1.1",
11-
"class-variance-authority": "^0.7.0",
10+
"@radix-ui/react-slot": "^1.1.2",
11+
"class-variance-authority": "^0.7.1",
1212
"clsx": "^2.1.1",
13-
"lucide-react": "0.456.0",
14-
"next-themes": "^0.4.3",
13+
"lucide-react": "^0.475.0",
14+
"next-themes": "^0.4.4",
1515
"react": "^19.0.0",
1616
"react-dom": "^19.0.0",
17-
"tailwind-merge": "^2.5.4",
17+
"tailwind-merge": "^3.0.1",
1818
"tailwindcss-animate": "^1.0.7",
19-
"zod": "^3.23.8"
19+
"zod": "^3.24.2"
2020
},
2121
"devDependencies": {
22-
"@turbo/gen": "^2.2.3",
23-
"@types/node": "^22.9.0",
24-
"@types/react": "18.3.0",
25-
"@types/react-dom": "18.3.1",
22+
"@tailwindcss/postcss": "^4.0.8",
23+
"@turbo/gen": "^2.4.2",
24+
"@types/node": "^20",
25+
"@types/react": "^19",
26+
"@types/react-dom": "^19",
2627
"@workspace/eslint-config": "workspace:*",
2728
"@workspace/typescript-config": "workspace:*",
28-
"autoprefixer": "^10.4.20",
29-
"postcss": "^8.4.47",
30-
"react": "^18.3.1",
31-
"tailwindcss": "^3.4.14",
32-
"typescript": "^5.6.3"
29+
"tailwindcss": "^4.0.8",
30+
"typescript": "^5.7.3"
3331
},
3432
"exports": {
3533
"./globals.css": "./src/styles/globals.css",
3634
"./postcss.config": "./postcss.config.mjs",
37-
"./tailwind.config": "./tailwind.config.ts",
3835
"./lib/*": "./src/lib/*.ts",
3936
"./components/*": "./src/components/*.tsx",
4037
"./hooks/*": "./src/hooks/*.ts"
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
/** @type {import('postcss-load-config').Config} */
22
const config = {
3-
plugins: {
4-
tailwindcss: {},
5-
autoprefixer: {},
6-
},
3+
plugins: { "@tailwindcss/postcss": {} },
74
};
85

9-
export default config;
6+
export default config;

0 commit comments

Comments
 (0)