大家好,我是Java1234_小锋老师。
一篇轻松读懂 shadcn/ui 是什么、为什么火、以及怎么上手的小文。
一、先说结论:它到底是什么?
如果你去 GitHub 搜前端 UI 相关的开源项目,shadcn/ui 几乎一定会出现在热门列表里。
一句话概括:shadcn/ui 不是那种「装个 npm 包就能用」的传统组件库,而是一套帮你把漂亮、好用的组件源码直接放进自己项目里的工具和方法。
官网有一句很直白的话:
This is not a component library. It is how you build your component library.
(这不是一个组件库,而是你搭建自己组件库的方式。)
所以,别把它想成 Material UI 或 Ant Design 那种「黑盒依赖」。你装下来的每一个按钮、对话框、表单,源码都在你的项目里,想改样式、改逻辑,直接打开文件改就行。

二、为什么和传统 UI 库不一样?
传统 UI 库的典型用法是这样的:
npm install xxx-ui- 从包里
import { Button } from 'xxx-ui' - 想深度定制时,往往要和组件提供的 props、主题变量较劲
shadcn/ui 换了一条路:
- 在项目里运行 CLI 命令
- 组件源码被复制到
components/ui/目录 - 从此这个组件属于你,和普通业务代码没区别
这种方式的好处很实在:
- 看得见:组件怎么写的,一目了然
- 改得动:不用和库的封装层斗智斗勇
- 好维护:团队可以按自己的设计规范慢慢演进
- AI 友好:代码在本地,AI 助手也更容易读懂和帮你改

三、项目基本情况
| 项目信息 | 说明 |
|---|---|
| GitHub 地址 | https://github.com/shadcn-ui/ui |
| 官方文档 | https://ui.shadcn.com/docs |
| 开源协议 | MIT |
| 主要语言 | TypeScript |
| 诞生时间 | 2023 年 1 月 |
| 社区热度 | GitHub Star 超过 11 万(持续增长中) |
项目由开发者 shadcn 发起,后来也成为 Vercel 生态里非常受欢迎的一部分。很多用 Next.js、React 的团队,都会把它当作「起步搭界面」的首选方案之一。
四、核心设计理念
官方文档里提到了几个关键词,翻译成大白话大概是:
1. 开放代码(Open Code)
组件不是藏在 node_modules 里的黑盒,而是实实在在的 .tsx 文件。你拥有它,也负责它。
2. 可组合(Composition)
各个组件的用法和结构比较统一,拼在一起不别扭,学习成本相对低。
3. 可分发(Distribution)
通过一套 schema 和 CLI 工具,把组件「分发」到不同项目里,还能对接社区注册表(Registry)。
4. 好看又好用(Beautiful Defaults)
默认样式已经挺讲究了,不想折腾设计的人可以直接用;想折腾的人也有足够空间。
5. 为 AI 时代准备(AI-Ready)
组件源码在本地、结构清晰,对 AI 编程助手、v0 这类工具都很友好------它们能读、能改、能帮你拼页面。
五、技术栈与组件生态
shadcn/ui 站在几个成熟方案的肩膀上:
- React:组件基于 React 编写
- Tailwind CSS:样式主要靠工具类完成,改起来直观
- Radix UI:负责无障碍、键盘交互、弹层行为等底层能力
- TypeScript:类型支持完善,开发体验舒服
常见组件包括:Button、Card、Dialog、Form、Table、Tabs、Toast 等,基本覆盖了后台系统、官网、SaaS 产品的大部分界面需求。
另外,它还支持多种框架场景(如 Next.js、Vite 等),并持续扩展对更多技术栈的适配。
六、使用流程一览
下面这张图展示了从「发现组件」到「在项目中使用」的大致流程:
#mermaid-svg-VtqwuH30SjJLBD2I{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VtqwuH30SjJLBD2I .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VtqwuH30SjJLBD2I .error-icon{fill:#552222;}#mermaid-svg-VtqwuH30SjJLBD2I .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VtqwuH30SjJLBD2I .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VtqwuH30SjJLBD2I .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VtqwuH30SjJLBD2I .marker.cross{stroke:#333333;}#mermaid-svg-VtqwuH30SjJLBD2I svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VtqwuH30SjJLBD2I p{margin:0;}#mermaid-svg-VtqwuH30SjJLBD2I .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VtqwuH30SjJLBD2I .cluster-label text{fill:#333;}#mermaid-svg-VtqwuH30SjJLBD2I .cluster-label span{color:#333;}#mermaid-svg-VtqwuH30SjJLBD2I .cluster-label span p{background-color:transparent;}#mermaid-svg-VtqwuH30SjJLBD2I .label text,#mermaid-svg-VtqwuH30SjJLBD2I span{fill:#333;color:#333;}#mermaid-svg-VtqwuH30SjJLBD2I .node rect,#mermaid-svg-VtqwuH30SjJLBD2I .node circle,#mermaid-svg-VtqwuH30SjJLBD2I .node ellipse,#mermaid-svg-VtqwuH30SjJLBD2I .node polygon,#mermaid-svg-VtqwuH30SjJLBD2I .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VtqwuH30SjJLBD2I .rough-node .label text,#mermaid-svg-VtqwuH30SjJLBD2I .node .label text,#mermaid-svg-VtqwuH30SjJLBD2I .image-shape .label,#mermaid-svg-VtqwuH30SjJLBD2I .icon-shape .label{text-anchor:middle;}#mermaid-svg-VtqwuH30SjJLBD2I .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VtqwuH30SjJLBD2I .rough-node .label,#mermaid-svg-VtqwuH30SjJLBD2I .node .label,#mermaid-svg-VtqwuH30SjJLBD2I .image-shape .label,#mermaid-svg-VtqwuH30SjJLBD2I .icon-shape .label{text-align:center;}#mermaid-svg-VtqwuH30SjJLBD2I .node.clickable{cursor:pointer;}#mermaid-svg-VtqwuH30SjJLBD2I .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VtqwuH30SjJLBD2I .arrowheadPath{fill:#333333;}#mermaid-svg-VtqwuH30SjJLBD2I .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VtqwuH30SjJLBD2I .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VtqwuH30SjJLBD2I .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VtqwuH30SjJLBD2I .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VtqwuH30SjJLBD2I .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VtqwuH30SjJLBD2I .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VtqwuH30SjJLBD2I .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VtqwuH30SjJLBD2I .cluster text{fill:#333;}#mermaid-svg-VtqwuH30SjJLBD2I .cluster span{color:#333;}#mermaid-svg-VtqwuH30SjJLBD2I div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VtqwuH30SjJLBD2I .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VtqwuH30SjJLBD2I rect.text{fill:none;stroke-width:0;}#mermaid-svg-VtqwuH30SjJLBD2I .icon-shape,#mermaid-svg-VtqwuH30SjJLBD2I .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VtqwuH30SjJLBD2I .icon-shape p,#mermaid-svg-VtqwuH30SjJLBD2I .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VtqwuH30SjJLBD2I .icon-shape .label rect,#mermaid-svg-VtqwuH30SjJLBD2I .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VtqwuH30SjJLBD2I .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VtqwuH30SjJLBD2I .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VtqwuH30SjJLBD2I :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 访问官方文档
选择需要的组件
运行 shadcn CLI
源码写入 components/ui
按项目需求修改样式或逻辑
在页面中引入并使用
整个过程不复杂,本质上就是:挑组件 → 拉源码 → 自己掌控。
七、快速上手示例
假设你已经有一个 React / Next.js 项目,大致步骤如下。
第一步:初始化
bash
npx shadcn@latest init
CLI 会问你用哪种风格、主题色、路径别名等,按提示选就行。
第二步:添加组件
比如想要一个按钮组件:
bash
npx shadcn@latest add button
执行完后,项目里会出现类似 components/ui/button.tsx 的文件。
第三步:在页面里使用
tsx
import { Button } from "@/components/ui/button"
export default function Page() {
return <Button>点击我</Button>
}
就这么简单。后续如果想把按钮改成圆角、加图标、换配色,直接改 button.tsx 里的 Tailwind 类名即可。
八、适合谁用?不太适合谁?
比较适合:
- 用 React 技术栈做产品的前端 / 全栈开发者
- 希望界面好看,但又想保留完全定制权的团队
- 已经在用 Tailwind CSS 的项目
- 想和 AI 工具配合快速搭界面的开发者
可能不太适合:
- 完全不想碰 Tailwind、只想纯 CSS 或 CSS-in-JS 方案的团队
- 希望「装包即用、绝不改源码」的场景
- 非 React 技术栈(除非有对应适配方案)
九、总结
shadcn/ui 之所以能在短时间内获得超高关注,不是因为它组件数量最多,而是它换了一种更务实的思路:
把组件库从「依赖包」变成了「你自己的代码」。
这既保留了开源社区的成熟实践(Radix、Tailwind),又把最终控制权交还给了开发者。对于想快速出活、又不想被 UI 框架绑死的团队来说,确实是一个很香的选择。
如果你正准备做一个新项目,或者受够了传统 UI 库改不动的痛点,不妨花十分钟跑一遍 CLI,亲手把一个 Button 组件「领」进项目里------用起来是什么感觉,比看十篇介绍都直观。