shadcn/ui学习笔记
shadcn/ui(常被口头叫 shad/ui)基础知识速览,偏向前端工程实战,适合已经会 React + Tailwind 的开发者快速上手。
# 一、shadcn/ui 是什么?
shadcn/ui ≠ 组件库
它是一个 组件源码集合 + CLI 工具
核心特点:
- ✅ 不是 npm 安装的黑盒组件
- ✅ 组件代码直接复制到你项目中
- ✅ 基于 Radix UI(无样式、可访问性强)
- ✅ 使用 Tailwind CSS 写样式
- ✅ 高度可定制、可维护
一句话:
你拥有组件,而不是依赖组件库
# 二、核心技术栈
| 技术 | 作用 |
|---|---|
| React | 组件系统 |
| Radix UI | 无障碍交互逻辑(Dialog / Dropdown / Popover 等) |
| Tailwind CSS | 样式系统 |
| class-variance-authority(CVA) | 组件变体管理 |
| lucide-react | 默认图标 |
| clsx + tailwind-merge | className 合并 |
# 三、安装与初始化(核心流程)
npx shadcn@latest init
1
会做的事:
检测你是否有 Tailwind
生成配置文件
components.json创建目录:
components/ ui/ lib/ utils.ts1
2
3
4
# 四、组件是怎么来的?
npx shadcn@latest add button
1
结果:
components/ui/button.tsx
1
👉 源码直接进你项目
// components/ui/button.tsx
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
outline: "border border-input bg-background",
},
size: {
sm: "h-9 px-3",
lg: "h-11 px-8",
},
},
defaultVariants: {
variant: "default",
size: "sm",
},
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 五、CVA(核心重点)
shadcn/ui 的灵魂
# 1️⃣ 为什么不用一堆 className?
❌ 坏方式:
<button className={`
px-4 py-2
${primary && "bg-blue-500"}
${size === "lg" && "text-lg"}
`} />
1
2
3
4
5
2
3
4
5
✅ shadcn/ui:
<Button variant="outline" size="lg" />
1
# 2️⃣ CVA 原理
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md font-medium",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
outline: "border border-input",
ghost: "hover:bg-accent",
},
size: {
sm: "h-9 px-3",
md: "h-10 px-4",
lg: "h-11 px-8",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
最终:
buttonVariants({ variant: "outline", size: "lg" })
1
# 六、Radix UI 的作用
Radix 提供的是:
- 键盘可访问性
- 焦点管理
- ARIA
- 行为逻辑
比如 Dialog:
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Title</DialogTitle>
</DialogHeader>
</DialogContent>
</Dialog>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
shadcn/ui 做的事:
- 给 Radix 组件 套 Tailwind 样式
- 统一 API 风格
# 七、主题系统(CSS Variables)
shadcn/ui 不写死颜色
:root {
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
}
1
2
3
4
2
3
4
使用时:
bg-primary text-primary-foreground
1
优势:
- 🌗 深色模式天然支持
- 🎨 主题切换成本极低
# 八、常用目录结构
components/
ui/
button.tsx
dialog.tsx
dropdown-menu.tsx
lib/
utils.ts // cn() 工具函数
1
2
3
4
5
6
7
2
3
4
5
6
7
utils.ts:
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
1
2
3
2
3
# 九、使用范式(很重要)
# 1️⃣ 组合而不是继承
<Button asChild>
<Link href="/login">Login</Link>
</Button>
1
2
3
2
3
asChild 基于 Radix Slot
# 2️⃣ 不要改 UI 组件逻辑
❌
components/ui/button.tsx
1
✅
components/common/submit-button.tsx
1
# 十、适合什么项目?
- ✅ 中大型 React / Next.js 项目
- ✅ 设计系统 / Design System
- ❌ 不适合“装完就用”的新手项目
# 十一、你学到什么程度算“会了”?
你能做到:
- 看懂 shadcn/ui 组件源码
- 自己写一个带 CVA 的组件
- 基于 Radix 封装业务组件
- 定制主题而不是改 class
# 十二、学习路径建议(给你一个进阶路线)
- 熟悉 Button / Input / Dialog 源码
- 学会 CVA
- 深入 Radix(Dialog / Popover / Dropdown)
- 自己封装一个组件(如:DataTable)
- 设计一套主题变量
上次更新: 2026/01/07, 09:20:46