Skip to content

一、Radix UI 是什么?一句话理解

  • Radix UI = Headless(无样式)的、可访问性优先的 React 交互组件原语

它提供:

  • ✅ 行为逻辑(open / close / focus)
  • ✅ 键盘交互
  • ✅ ARIA 属性
  • ✅ 状态管理
  • ❌ 不提供样式

👉 它是“交互层”,不是“UI 层”

二、为什么 Radix UI 很重要?

如果你自己写一个 Dialog,需要处理:

  • ESC 关闭
  • 焦点锁定(focus trap)
  • Tab 循环
  • aria-modal
  • 屏幕阅读器
  • Portal

👉 Radix 全帮你搞定,而且符合 WAI-ARIA 标准

三、Radix UI 的核心设计哲学

1️⃣ Headless(无样式)

tsx
<DialogContent className="bg-white rounded" /-

样式完全由你控制

2️⃣ Compound Components(组合组件)

tsx
<Dialog>
  <DialogTrigger />
  <DialogContent />
</Dialog>
  • 父组件提供 context
  • 子组件消费 context
  • 强约束、强语义

3️⃣ 状态可控 / 不可控

tsx
<Dialog open={open} onOpenChange={setOpen} />

或者:

tsx
<Dialog defaultOpen />

4️⃣ Accessibility First(不是事后补)

Radix 的每一个 API 都围绕可访问性设计。

四、Radix UI 组件分类

Overlay 类(最重要)

  • Dialog
  • AlertDialog
  • Popover
  • Tooltip
  • DropdownMenu
  • ContextMenu

👉 90% 的交互来自这里

Form & Input

  • Checkbox
  • RadioGroup
  • Switch
  • Slider
  • Select
  • Tabs
  • Accordion
  • NavigationMenu

五、核心机制一:Trigger / Content

tsx
<Popover>
  <PopoverTrigger>Open</PopoverTrigger>
  <PopoverContent>Content</PopoverContent>
</Popover>

Radix 内部:

  • Trigger 控制 open
  • Content 响应 open
  • 状态通过 context 共享

六、asChild(非常重要)

为什么要 asChild?

tsx
<DialogTrigger>
  <Button />
</DialogTrigger>

❌ 会多包一层 DOM

正确方式

tsx
<DialogTrigger asChild>
  <Button />
</DialogTrigger>

👉 不新增 DOM,只注入行为

底层用的是 Slot

七、Portal(解决层级问题)

tsx
<DialogPortal>
  <DialogContent />
</DialogPortal>
  • 渲染到 body
  • 避免 z-index 地狱

八、Radix 的 State & Data Attributes

Radix 会自动注入:

html
data-state="open"
data-disabled
data-side="top"

你可以直接用 Tailwind:

tsx
className="
  data-[state=open]:animate-in
  data-[state=closed]:animate-out
"

👉 这是 shadcn/ui 动画的关键

九、受控 vs 非受控(一定要懂)

非受控(简单)

tsx
<Dialog defaultOpen />

受控(推荐在业务中)

tsx
<Dialog open={open} onOpenChange={setOpen} />

十、以 Dialog 为例(完整解构)

tsx
<Dialog>
  <DialogTrigger asChild>
    <Button>Open</Button>
  </DialogTrigger>

  <DialogContent>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
      <DialogDescription>Desc</DialogDescription>
    </DialogHeader>
  </DialogContent>
</Dialog>

Radix 负责:

  • open 状态
  • ESC
  • focus trap
  • aria-describedby

shadcn/ui 负责:

  • className
  • 动画
  • 结构封装

十一、常见误区

  • ❌ Radix 当 UI 库用
  • ❌ 在 Trigger 里写业务逻辑
  • ❌ 忽略 data-state
  • ❌ 不用 asChild

十二、Radix UI + shadcn/ui 的关系

Radixshadcn/ui
交互原语样式封装
无样式Tailwind
a11yDesign System
行为视觉

十三、你什么时候算“会 Radix UI”?

你能:

  • 手写 Dialog / Popover / Tabs
  • 正确使用 asChild
  • 利用 data-state 写动画
  • 封装而不是直接使用 Radix