post cover

技术热点落地: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 initnpx 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

迁移工具会:

  1. 逐个组件迁移(你指定一个,它就迁移一个)
  2. 每迁移一个组件生成一个 git commit,独立分支操作
  3. .migration/ 目录留下详细报告
  4. 迁移过程中新旧库可以共存

关键实现细节

Base UI 与 Radix 的 API 差异速查

差异点RadixBase UI
渲染属性asChildrender
包名@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 继续支持
  • 活跃项目 → 渐进迁移,按组件逐个切换,风险最低

最关键的一条原则:不需要为了切换而切换。 等项目自然重构时顺手完成即可。


参考:https://ui.shadcn.com/docs/changelog