技术热点落地:shadcn/ui 从 Radix 切换到 Base UI 完整迁移指南(2026-07-06)
适用场景与目标
背景
2026 年 7 月,shadcn/ui 官方宣布默认组件库从 Radix 切换为 Base UI。Base UI 由原 Radix 核心团队打造,目前版本 1.6.0,周下载量 600 万+。社区新项目的选择比例已经达到 Base UI : Radix = 2 : 1,这次切换只是「让默认值追上社区选择」。
这件事为什么重要
- shadcn/ui 是 React 生态最流行的组件库(GitHub 118k stars),影响面巨大
- 如果你是前端开发者、React 项目维护者、或正考虑用 shadcn/ui 搭建新产品,这次变更会直接影响你的项目初始化流程
- 现有 Radix 项目不必迁移,但新项目默认用 Base UI——不了解差异会遇到诡异的 bug
本文目标读者
- 新项目启动者:用 Base UI 从零搭建 shadcn/ui 项目
- 已有 Radix 项目维护者:评估是否迁移、如何渐进迁移
- CI/CD 或脚本使用者:确保非交互式初始化的兼容性
最小可行方案(MVP)步骤
方案 A:新项目默认 Base UI(推荐)
这是目前最简单的方式——什么都不用做,默认就是 Base UI。
# 1. 创建 Next.js 项目(或其他框架)
npx create-next-app@latest my-app
cd my-app
# 2. 初始化 shadcn/ui(默认 Base UI)
npx shadcn@latest init
# 3. 安装组件(自动使用 Base UI 版本)
npx shadcn@latest add button card dialog
就这么简单。 初始化时不需要传任何额外参数,Base UI 是默认选择。
方案 B:新项目仍用 Radix(保留旧行为)
如果你对 Radix 很熟悉、项目依赖 Radix 特有 API,或者团队还不打算学习 Base UI 差异:
npx shadcn@latest init -b radix
这个 -b radix 参数可以加在任何 shadcn init 或 npx shadcn add 命令后面。
CI/CD 提醒:如果你有自动化脚本或 CI 流程在跑
shadcn init,务必检查默认值是否变了。非交互式环境下,不指定-b radix将默认使用 Base UI。
方案 C:现有 Radix 项目渐进迁移(重点)
官方提供了一个渐进式迁移工具——它不是 codemod,而是以 skill(技能)的形式集成到 AI 编码助手中,让 AI 逐个组件地迁移。
# 1. 安装迁移 skill
pnpm dlx skills add shadcn/ui
# 2. 在 AI 编码工具中(如 Claude Code、Cursor)执行
# migrate accordion to base-ui
迁移工具会:
- 逐个组件迁移(你指定一个,它就迁移一个)
- 每迁移一个组件生成一个 git commit,独立分支操作
- 在
.migration/目录留下详细报告 - 迁移过程中新旧库可以共存
关键实现细节
Base UI 与 Radix 的 API 差异速查
| 差异点 | Radix | Base UI |
|---|---|---|
| 渲染属性 | asChild | render |
| 包名 | @radix-ui/* | @base-ui-components/* |
| 样式方案 | 需自行封装 | 同类(headless,无内置样式) |
| 无障碍 | 成熟 | 同样优秀,团队同一批人 |
| 社区组件数 | 稳定 | 持续新增自有组件 |
迁移报告示例
执行迁移后,每个组件会在 .migration/ 下生成类似这样的报告:
# accordion
<!-- date, strategy used, and verdict -->
## Changed
- accordion.tsx → 替换 import 路径,改用 render 替代 asChild
- page.tsx → 更新 AccordionTrigger 的调用方式
## Left alone
- custom-accordion.tsx → 外表类似但实际是自定义组件,未改动
## Behavior changes
- AccordionContent 的 mount 行为:Base UI 默认 unmount,Radix 默认保持 DOM
## Verify by hand
- [ ] 点击 accordion 项检查展开/收起动画
- [ ] Tab 导航顺序正常
- [ ] 移动端触摸响应正常
新旧库共存的原理
迁移期间,package.json 中同时存在 @radix-ui/* 和 @base-ui-components/*。shadcn/ui 的组件代码是复制到你项目中的(不是 npm 依赖),所以每个组件明确引用其中一个库。你可以逐个迁移,未迁移的组件继续用 Radix,已迁移的用 Base UI,两者互不干扰。
常见坑与规避清单
🚫 坑 1:CI/CD 脚本初始化失败
症状:自动化部署脚本中 shadcn init 突然开始使用 Base UI,导致组件在不同环境下行为不一致。
解决:所有非交互式初始化命令加 -b 参数:
# 明确指定库
npx shadcn@latest init -b radix # 强制用 Radix
npx shadcn@latest init -b base-ui # 显式用 Base UI(也可省略,因为已经是默认)
🚫 坑 2:asChild → render 不兼容
症状:迁移后 TypeScript 报错 Property 'asChild' does not exist on type ...
解决:Base UI 使用 render prop 替代 asChild:
// Radix 写法(旧)
<DropdownMenuTrigger asChild>
<button>Open</button>
</DropdownMenuTrigger>
// Base UI 写法(新)
<DropdownMenuTrigger render={<button />}>
Open
</DropdownMenuTrigger>
🚫 坑 3:自定义 registry 未指定库
症状:你的私有 registry 组件自动使用 Base UI,但你以为它用 Radix。
解决:在 registry 配置中明确指定:
{
"name": "my-button",
"type": "registry:ui",
"registry:base": "radix" // 显式锁定
}
🚫 坑 4:迁移工具的进度丢失
症状:换一台机器或换一个 AI 工具后发现迁移进度不明确。
解决:迁移进度全部在 git history 里——每个组件一个独立 commit,迁移分支不合并。任何时候切换环境都:
git log --oneline migration/base-ui # 看迁移到哪了
git diff HEAD..migration/base-ui # 看还剩什么
🚫 坑 5:Behavior change 被忽略
症状:迁移后组件看起来正常但交互行为有微妙差异(比如 Accordion 的 mount/unmount 行为)。
解决:仔细阅读每个迁移报告的 ## Behavior changes 和 ## Verify by hand 部分。AI 只改 API,不改行为逻辑。手动验证永远不可跳过。
成本/性能/维护权衡
🔄 要不要迁移?决策树
你的项目是否已有大量 Radix 组件?
├── 是,且运行良好
│ └── ✅ 不迁移。Radix 不会被废弃,继续维护。
├── 是,但即将大改版
│ └── 🔄 渐进迁移。趁重构逐个组件迁移。
├── 否,正在启动新项目
│ └── ✅ 默认 Base UI。省心。
└── 否,但团队有 Radix 经验
└── 🤔 可选。用 -b radix 继续使用 Radix。
📊 成本对比
| 维度 | 保持 Radix | 迁移到 Base UI |
|---|---|---|
| 学习成本 | 0(已有经验) | 低(API 相似,重点在 asChild→render) |
| 迁移成本 | 0 | 中(per-component 渐进,50 组件约 25 分钟) |
| 长期维护 | 继续更新,但新组件可能 Base UI 优先 | 与官方对齐,新组件原生支持 |
| 风险 | 低(成熟稳定) | 低(逐步切换,可回滚) |
⚡ 性能差异
Base UI 和 Radix 在 Runtime 性能上差异不大,两者都是 headless 设计。Base UI 的一些新组件(如 MessageScroller)有专门优化过的 scroll behavior,对聊天类应用有明确优势。
一周内可执行行动清单
Day 1:评估(5 分钟)
# 查看项目使用的 shadcn 组件列表
grep -r "from \"@radix-ui/" src/components/ui/ | head
# 统计 Radix 组件数量
grep -rl "from \"@radix-ui/" src/components/ui/ | wc -l
Day 2:新项目试水(10 分钟)
# 用 Base UI 全新初始化一个 demo 项目,验证工作流
mkdir -p shadcn-base-demo && cd shadcn-base-demo
npx shadcn@latest init -b base-ui --defaults
npx shadcn@latest add button card dialog dropdown-menu
Day 3:配置 CI/CD(5 分钟)
检查所有 CI/CD 脚本中 shadcn init 的调用,显式加入 -b radix 或 -b base-ui。
Day 4:迁移试点(30 分钟)
对现有 Radix 项目中最简单的 3 个组件(如 Button、Badge、Card)做迁移试点:
pnpm dlx skills add shadcn/ui
# 然后在 AI 编码工具中: "migrate button to base-ui"
# 检查 .migration/button.md 报告
Day 5:团队同步
- 在团队 Wiki 记录 Base UI vs Radix 的 API 差异
- 统一新项目的默认选择
- 讨论是否需要整体迁移及时间表
Day 6-7:批量迁移(可选)
如果决定迁移,分批进行,每批 5-10 个组件,每次迁移后跑完整测试 + 手动验证 checklist。
总结
shadcn/ui 的默认库切换是 React 前端生态的一个标志性事件——这意味着经过 3 年多的发展,组件库的「下一站」已经明确。Base UI 与 Radix 出自同一团队,不存在「换人重做」的风险。
对于大多数团队:
- 新项目 → 直接用 Base UI,零配置
- 稳定项目 → 不迁移,Radix 继续支持
- 活跃项目 → 渐进迁移,按组件逐个切换,风险最低
最关键的一条原则:不需要为了切换而切换。 等项目自然重构时顺手完成即可。