AI Coding 时代,最适合 Web 开发的 UI 库:shadcn

AI Codingshadcn前端

AI Coding 时代,最适合 Web 开发的 UI 库:shadcn

AI Coding 之后,UI 库的评价标准变了。

以前选组件库,主要看组件全不全、默认样式好不好看、文档是否成熟。现在还要看另一件事:AI 能不能读懂这套 UI,能不能沿着已有代码继续写,能不能在修改时不破坏项目原有风格。

从这个角度看,shadcn 适合现在的 Web 开发。

它的价值不只是默认样式,而是组件源码进入项目之后,UI 不再是一个外部黑盒。人可以改,AI 也可以读。这一点在频繁使用 AI 改页面、补状态、重构组件时,会变得越来越重要。

传统组件库的问题不在能力,而在边界

传统组件库仍然有价值。

Element Plus、Ant Design、TDesign 这类组件库,在标准后台页面里效率高。表格、表单、弹窗、菜单、日期选择、上传等能力已经成熟,团队也容易形成统一写法。

问题通常出现在更后面。

项目开始有自己的视觉密度、交互习惯、移动端适配、业务状态、表格操作列、复杂弹窗表单。这个阶段往往会出现大量 wrapper、样式覆盖和局部补丁。

人可以靠经验维护这些补丁。AI 参与之后,问题会更明显。

AI 能看到页面怎么使用组件,但看不到组件内部怎么实现。遇到样式覆盖、插槽结构、交互细节时,它只能根据文档和现有代码推断。推断不稳定,生成出来的代码就容易变成新的补丁。

所以,AI Coding 时代更适合这样的 UI 方案:

  • 基础组件在项目源码里;
  • 组件粒度足够小,方便组合;
  • 样式通过 token 表达,而不是散落硬编码颜色;
  • 项目可以在基础组件上沉淀自己的业务组件;
  • React 和 Vue 项目能沿用接近的组织方式。

shadcn 刚好满足这些条件。

组件源码属于项目,AI 才能接着写

shadcn 不太像传统意义上的组件库。

传统组件库一般是安装 npm 包,然后从包里 import 组件。shadcn 更像一套组件源码分发方式:需要 Button,就用 CLI 把 Button 加进项目;需要 Dialog,就把 Dialog 加进项目。添加之后,组件代码就在 components/ui 下面,由项目自己维护。

这个差异关键。

组件源码在项目里,意味着 AI 可以看到它的 props、class、组合方式和设计 token。后续让 AI 新增页面或调整交互时,它不是只面对一个黑盒 API,而是能参考项目真实的 UI 基础层。

这也会改变组件抽象的方式。

基础组件不需要一次性覆盖所有业务场景。它只要保持清晰、稳定、可组合。真正贴近业务的部分,可以继续往上沉淀成 DataTableFormProProTableMobileCard 这类项目级组件。

React 和 Vue 可以共享同一套组织方法

shadcn 的另一个优势,是思想可以跨框架迁移。

在一个 Vue + Vite 后台项目里,可以使用 shadcn-vue,基础组件放在 src/components/ui,样式入口放在 src/style.css。底层能力来自 Reka UI、Tailwind CSS、lucide-vue-next、vue-sonner、TanStack Vue Table、Zod 等。

在一个 React + Next.js 项目里,可以使用 shadcn/ui,基础组件同样放在 src/components/ui,样式入口放在 src/app/globals.css。底层能力来自 Radix、Tailwind CSS、lucide-react、sonner、React Hook Form、Zod 等。

框架不同,但组织方式接近:

  • components/ui 放基础组件;
  • components/ui-procomponents/system 放项目级组合;
  • 全局 CSS 维护设计 token;
  • 页面主要负责业务状态、请求和组合;
  • 表格、表单、弹窗这类高频结构在项目层继续封装。

这对 AI 协作有直接影响。

AI 不需要每次都重新理解“这个项目的表格长什么样”“移动端卡片密度是多少”“状态徽标怎么写”。只要项目组件分层清楚,它就可以沿着已有组件继续生成代码。

Vue 项目适合沉淀 ui-pro

在 Vue 后台项目里,components/ui 更适合作为基础层。

这里放 buttoncarddialogdrawerformfieldinputselecttablepaginationsonnerdate-picker 等组件。它们解决的是通用 UI 能力,不直接绑定业务字段。

后台系统更高频的问题,通常不是单个按钮或输入框,而是“搜索表单 + 表格 + 分页 + 操作列 + 弹窗表单”这一类组合。

这类能力适合沉淀到 components/ui-pro

例如 DataTable 可以组合 CardTableSelectSkeletonButton,并接入 TanStack Vue Table。页面只声明列配置、请求函数和操作按钮,不重复处理加载态、空状态、分页和横向滚动。

FormPro 则可以把 Zod 校验、字段布局、必填标记、禁用状态收在一起。页面继续关心字段和提交逻辑,不需要每次重新组织表单结构。

这不是为了把页面写成配置,而是为了把重复结构从页面里拿出去。

React 项目适合沉淀 system 组件

React + Next.js 项目里的分层也类似。

components/ui 里放基础组件,例如 buttoncarddialogsheetselecttablepaginationcheckboxinputpopoversonnerdate-picker

components/system 则更适合放产品形态相关的组合组件,例如 desktop-shellmobile-shellworkspace-viewpage-headerpro-tablemobile-cardmetric-cardempty-state

pro-table 负责处理列宽、固定列、分页 token、选中行和筛选栏。mobile-card 负责移动端卡片的密度、圆角和间距。它们都不是通用开源组件,却是一个项目能否保持一致性的关键。

AI 生成页面时,如果直接使用基础组件,结果经常会“能用但不统一”。如果让它优先复用 system 组件,新页面会更接近项目已有风格。

shadcn 的成本是需要项目纪律

shadcn 的自由度高,也意味着团队要有更明确的边界。

基础组件可以改,但不应该随意改。components/ui 里尽量保持通用能力,业务差异放到 ui-prosystem 层。

Tailwind 写起来快,但不能把页面变成一次性 class 的堆叠。颜色、圆角、边框、背景、前景色、ring、muted、accent 这些东西,应该尽量通过 token 表达。

AI 也需要约束。

写页面前,先看项目已有组件。能复用 DataTableFormProProTableMobileCard,就不要重新拼一套相似结构。需要新增抽象时,也应该先判断它是不是会被复用,而不是为单个页面创建复杂组件。

更推荐的项目分层

经验上,shadcn 项目可以按三层组织。

第一层是 components/ui

这里放 CLI 添加来的基础组件,以及少量与设计 token 相关的统一调整。它们应该足够通用,不包含业务接口和业务字段。

第二层是 components/ui-procomponents/system

这里放项目级组合组件。表格、搜索栏、弹窗表单、移动端卡片、页面头部、统计卡片、确认弹窗,都适合放在这一层。

第三层是页面。

页面主要处理路由参数、接口请求、业务状态、弹窗开关和提交逻辑。复杂 UI 结构不应该在每个页面重复写。

这样组织之后,AI 参与开发时能更容易判断:什么是基础能力,什么是项目约定,什么是当前页面的业务逻辑。

结语

shadcn 的价值不在于默认样式,而在于它改变了组件库和项目的关系。

传统组件库更像外部依赖。shadcn 则把组件变成项目源码的一部分,让组件可以被阅读、修改和继续沉淀。

在纯人工开发时,这已经能降低深度定制的成本。

在 AI Coding 逐渐进入日常开发之后,这个优势会更明显。AI 不适合长期面对封闭、复杂、只能查文档的组件黑盒。它更适合面对清晰、可读、可组合、能在项目里继续演进的 UI 代码。

从 Vue 后台项目到 React/Next 业务系统,shadcn 都能提供同一套组织方法。它不是只能服务某一个框架的组件库,而是一种更适合现代 Web 项目的 UI 工程方式。