设计原则
复杂交互组件的风险通常不在样式,而在焦点管理、键盘路径、ARIA 语义、portal、碰撞定位和移动端滚动锁定。Primitive 的价值是把底层行为先稳定下来。
大理论
可访问交互组件应先解决行为契约,再做视觉表达。弹窗、菜单、popover、tabs、accordion、select 和 slider 这类组件如果从零手写,最容易漏掉键盘、焦点返回、屏幕阅读器标签和 touch 场景。
小知识点
- Radix Primitives 适合需要细粒度焦点控制、碰撞定位、方向键和 ARIA 模式的 React 组件。
- Headless UI 适合 Tailwind/React/Vue 项目中范围较清晰的无样式可访问组件。
- 选 primitive 不是放弃设计系统,而是把视觉 token、variant 和布局规则接到稳定行为上。
- primitive 组件进入项目后必须补齐 loading、empty、error、disabled、reduced-motion 和 mobile 状态。
设计判断
如果组件需要 focus trap、Escape 关闭、焦点返回、方向键移动或 screen reader 语义,就不要先写 div 版本;先确认是否有 Radix 或 Headless UI 能覆盖行为。
实现建议
建立组件选择记录:用户任务、候选 primitive、必须状态、键盘路径、ARIA 约束、样式 token、移动端差异和测试要点。实现时只暴露业务需要的 props,不把底层 primitive API 原样泄露给页面。
反例/风险
手写下拉菜单只支持鼠标、Dialog 关闭后焦点丢失、Popover 在移动端遮住触发器、Tabs 无方向键导航、Select 只靠颜色表达选中态。
案例分析
Radix Primitives 官方定位为无样式、可访问、开源 React primitives,并展示 Dialog、Dropdown Menu、Popover、Slider、Tabs 等行为能力;Headless UI 也强调 completely unstyled 和 fully accessible。可学习点是:把行为复杂度交给成熟 primitive,把品牌和产品语义留给本地组件层。
来源链接
Radix Primitives: https://www.radix-ui.com/primitives Radix GitHub: https://github.com/radix-ui/primitives Headless UI: https://headlessui.com/ Headless UI GitHub: https://github.com/tailwindlabs/headlessui
Agent 指令
遇到复杂交互组件时先列出行为要求,再选择 Radix、Headless UI 或原生控件;最后才写样式和 variant。