Base UI:把自己从组件样式的泥潭里捞出来
如果你曾经为了改一个 Ant Design 或者 MUI 的默认样式而写了几十行 !important,或者在深夜纠结为什么手写的下拉菜单无法用键盘操作,那你一定要了解一下 Base UI。
到底什么是 Base UI?
简单来说,Base UI 是由 MUI 团队打磨的一套 Headless(无样式) React 组件库。
它只给你“骨架”和“大脑”——也就是组件的逻辑、交互、状态管理以及极其麻烦的无障碍访问性 (A11y)。至于它的皮囊(样式),它完全交给你来决定。
它的幕后推手包括 MUI 团队和 Radix UI 的原作者之一。你可以把它看作是吸取了 MUI 的稳健经验,又融入了 Radix 现代设计理念的产物。
为什么我推荐你在新项目里试试它?
1. 彻底解决“样式覆盖地狱”
Base UI 没有默认的 CSS。这意味着你不需要去猜 CSS 类名,也不需要和它自带的边距、颜色死磕。无论你是用 Tailwind CSS、CSS Modules 还是 Emotion,你直接把类名挂在组件上就行。
2. 它是“无障碍访问”的救星
写一个能用的组件很容易,但写一个能让所有人(包括依赖键盘或屏幕阅读器的用户)都好用的组件非常难。Base UI 按照 WAI-ARIA 标准处理了焦点管理、键盘导航等细节。这些琐事,让它去操心就好。
3. 极好的灵活性与性能
- 组合化 API:它的组件设计遵循“组合优于继承”。
- Hooks 模式:如果你连它的 DOM 结构都不想要,它还提供了
useButton、useMenu等 Hooks,让你只复用逻辑,UI 彻底自定义。 - Tree-shaking:只打包你用到的部分,体积控制得非常好。
避坑指南:它不适合所有人
在决定尝试之前,得先泼盆冷水:
- 它没有“开箱即用”的视觉效果。如果你引入一个 Button,它看起来就是原生的样子,甚至没有宽窄高矮。
- 前期开发慢。你必须自己手写 CSS。如果你的目标是两天撸出一个后台管理系统,别选它,去用 Ant Design 或者 Mantine,那些更适合“快餐式”开发。
- 生态还在成长期。虽然背后是大厂,但相比已经风靡全球的 Radix UI 生态(比如各种 shadcn 克隆版),Base UI 的现成模版目前还少一点。
怎么上手?
Base UI 的上手流程并不复杂,但你需要适应一种“拼积木”的思维。
1. 第一步:把包装上
选一个你喜欢的包管理器:
# npm
npm install @base-ui/react
# pnpm (推荐,省空间)
pnpm add @base-ui/react
# yarn
yarn add @base-ui/react
2. 第二步:理解组件结构(以 Popover 为例)
Base UI 的组件通常不是一个大的标签,而是一组协同工作的“零件”。
import { Popover } from "@base-ui/react/popover";
export default function MyPopover() {
return (
<Popover.Root>
{/* 1. 触发器:点击它就会弹出 */}
<Popover.Trigger className="trigger-style">点击我</Popover.Trigger>
{/* 2. Portal:把内容“传送”到 body 底部,防止被父元素的 overflow: hidden 裁掉 */}
<Popover.Portal>
{/* 3. Positioner:这可是个宝贝,它负责计算弹出框的位置 (左边、右边、对齐等) */}
<Popover.Positioner sideOffset={8}>
{/* 4. Popup:这才是你写内容的地方 */}
<Popover.Popup className="popup-content">
<Popover.Title>嘿,我是标题</Popover.Title>
<Popover.Arrow className="arrow" />
<p>这里的内容随你写,样式也随你定。</p>
</Popover.Popup>
</Popover.Positioner>
</Popover.Portal>
</Popover.Root>
);
}
3. 第三步:样式怎么搞?(以 Tailwind 为 例)
因为 Base UI 的组件会根据状态自动挂载 data-* 属性,你可以非常优雅地处理状态样式。
<Popover.Popup
className="
bg-white p-4 border rounded shadow-xl
/*
这里是重点!当 Popover 打开时,
我们可以通过 data-state 来控制动画或样式
*/
data-[state=open]:animate-in
data-[state=open]:fade-in
"
>
{/* 内容 */}
</Popover.Popup>
选 Base UI 还是 Radix UI(甚至 Shadcn UI)?
这是很多人纠结的问题。其实它们的关系是这样的:
- Base UI vs Radix UI:它们是直接的对手。目前 Radix UI 更加成熟,生态更广;但 Base UI 在 MUI 的加持下,在某些复杂表单项(比如 Select、Combobox)的交互细节上做得更深,且 API 设计上试图更进一步。
- Base UI vs Shadcn UI:Shadcn 其实是在 Radix 之上包了一层“好看的 Tailwind 样式”。你完全可以使用 Base UI 作为底层,自己造一个属于你公司的 "Shadcn"。
总结建议
- 选它:如果你正在为公司构建一套长久使用的 Design System,追求高度的视觉统一和交互体验,又不差那点写 CSS 的时间。
- 别选它:如果你只是想快速上线一个原型,或者你并不想深入处理复杂的 CSS 布局。
Base UI 不是要取代谁,而是给那些追求完美的开发者一个“解救方案”。