跳到主要内容

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 结构都不想要,它还提供了 useButtonuseMenu 等 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 也完全可以作为底层,再往上搭一套属于团队自己的组件体系。

总结建议

  • 选它:如果当前在为团队构建一套长久使用的 Design System,追求高度的视觉统一和交互体验,也愿意投入一些 CSS 成本。
  • 别选它:如果目标只是快速上线一个原型,或者暂时不想深入处理复杂的 CSS 布局。

Base UI 不是要取代谁,而是给那些追求完美的开发者一个“解救方案”。