Headless UI
Tailwind Labs 官方出品的「Headless / Unstyled」组件库 + Tailwind CSS 黄金搭档、Catalyst 设计系统的底层引擎——由 Tailwind Labs(Tailwind CSS 母公司、Adam Wathan + Steve Schoger 团队)开发并长期维护,最早 2020 年 4 月发布 v0.1,2021 年 9 月发布 v1.0,2024 年 5 月正式发布 v2.0(重大重写)—— Headless UI 把自己定位为「给 Tailwind 用户的完美 a11y 组件层」:不提供任何样式 + 不提供任何主题 + 不强制布局 + 只提供行为 + 键盘 + 焦点 + a11y。截至 2026 年 5 月稳定版 v2.2.x(仅 React 版;Vue 版仍停留在 v1.7——这是 Headless UI 当前最大的「生态不对称」事实)。GitHub 27k+ Star、月下载量 1.6 亿+。
与 Radix UI / Ark UI 的根本区别:
- 作者背景:Headless UI 由 Tailwind 团队亲自维护——所有 API / 类名 / data-* 属性都为 Tailwind 量身定制(
data-[hover]:bg-blue-500/data-[checked]:ring-2等是它的母语)。Radix 由 WorkOS 维护、Ark UI 由 Chakra 团队(Adobe React Aria 系)维护 - 组件数量:Headless UI 仅 16 个组件(v2.x 全清单:Menu / Listbox / Combobox / Dialog / Disclosure / Popover / Tabs / Transition / Switch / RadioGroup / Checkbox / Input / Select / Textarea / Fieldset / Button)。vs Radix Primitives 30+——Headless UI 聚焦最常用场景、不追求大而全
- 框架支持:Headless UI 只支持 React + Vue(没有 Svelte / Solid / Angular)。Radix 只 React、Ark UI 支持 React + Vue + Solid。但 Vue 版仅 v1.7、未跟进 v2——Vue 用户实际能享受到的 Headless UI 体验显著弱于 React 用户
- 设计哲学:Headless UI 「Tailwind 一等公民、其他次之」。Radix 「任何 CSS 方案皆可」。Ark UI 「框架无关、状态机驱动」——三者各有取舍
<Field>表单封装:v2.0 引入的 Field / Fieldset / Label / Description / Input / Select / Textarea / Legend 这套表单 Primitive 自动注入 ARIA(aria-labelledby/aria-describedby/id全部自动生成)——Radix Form 也做了类似事情、但 Headless UI 的 API 更轻量
Headless UI v2 核心特性:Built-in Anchor Positioning(v2 杀手锏:基于 Floating UI 直接内置到 Menu / Popover / Combobox / Listbox 的 anchor prop,自动 collision detection + 自动 portal + CSS 变量配置——无需自己安装 Floating UI、无需 ref、无需 manual position) / data- 属性 + Tailwind 完美集成*(data-[hover]:bg-blue-500 / data-[focus]:ring-2 / data-[checked]:bg-indigo-600 / data-[open]:rotate-180——所有状态都通过 data-* 暴露、Tailwind variant 直接命中) / 基于 React Aria 的智能状态检测(data-active 拖出 trigger 区域自动消失 / data-hover 触摸设备自动忽略 / data-focus 等价 :focus-visible 无误触发)/ 新增 8 个 HTML 表单组件(v2 引入:Checkbox / Input / Select / Textarea / Fieldset / Legend / Field / Label / Description —— 自动 wiring aria-labelledby / aria-describedby / id)/ Combobox 虚拟滚动(基于 TanStack Virtual —— virtual={{ options: filteredPeople }} 一行启用、轻松 10000+ 选项)/ Render Props + data- 双模式*(既支持 v1 风格的 {({ open }) => ...} 渲染函数、也支持 v2 风格的 className="data-[open]:bg-red-500") / as Prop 自由切换 DOM 元素(as={Fragment} / as="a" / as={MyButton}) / Portal 默认 + 自动 modal 焦点陷阱 / Transition 内置(transition prop + data-closed / data-enter / data-leave —— 不需要 Framer Motion 即可写完整动画) / TypeScript-first / SSR 完美
典型用户群:全球 React 开发者 + Tailwind 重度用户 + Next.js / Remix / Vite SSR 项目 + 个人开发者 + 海外 SaaS 团队。Headless UI 是 Tailwind 用户的「默认 a11y 组件层」——几乎所有用 Tailwind 写自定义组件的开发者都用过 Headless UI。Tailwind UI(付费 UI 库)和 Catalyst(Tailwind 官方设计系统)也都基于 Headless UI 构建。
Headless UI 是 React UI 库生态位最专注的一员——它不与 Radix / Ark / shadcn 抢「最大覆盖率」,它只做「Tailwind 用户最舒服的 a11y 组件」。如果你主要在用 Tailwind + 不需要 Radix 的 30+ 复杂组件 + 想要最轻量的 headless 方案,那 Headless UI 就是 React / Vue 生态最自然的选择。截至 2026 年的 Headless UI 处于「React v2 持续演进 + Vue v1 维护中 + Tailwind UI / Catalyst 加持」三位一体期——是 Tailwind 生态事实必备的 a11y 基建库。
评价
优点
Tailwind 官方出品、API 为 Tailwind 量身定制:Headless UI 的所有状态属性都用
data-*(data-open/data-closed/data-focus/data-hover/data-active/data-checked/data-disabled/data-selected)—— 配合 Tailwind 的data-[hover]:/data-[open]:variant 极致丝滑。vs Radix data-state="open"——Headless UI 的命名更扁平、Tailwind variant 写起来更短v2.0 内置 Anchor Positioning 是革命性升级:基于 Floating UI 直接集成到 Menu / Popover / Combobox / Listbox 的
anchorprop。anchor="bottom start"+[--anchor-gap:8px]一行搞定完整 collision detection + 自动 portal。vs RadixsideOffset+ 手动 Portal——Headless UI 的 API 更高级(直接读 CSS 变量配置而不是 props)<Field>表单 Primitive 自动注入 ARIA:v2.0 新增的 Field / Fieldset / Legend / Label / Description / Input / Select / Textarea —— 自动生成id/aria-labelledby/aria-describedby/ 自动级联 disabled。vs Radix Form 仍需手动写Form.Field name=...——Headless UI 的表单 API 是这几个 headless 库里最优雅的Combobox 虚拟滚动开箱即用:基于 TanStack Virtual。
virtual={{ options: filteredPeople }}+ ComboboxOptions render prop——10000+ 选项无性能损失。vs Radix Select / Combobox 没有官方虚拟滚动方案——Headless UI 在「大数据 dropdown」场景优势明显基于 React Aria 的智能状态检测:v2 之后使用 React Aria 库的状态检测引擎 ——
data-active在拖出按钮区域自动消失、data-hover触摸设备自动忽略、data-focus等价:focus-visible无误触发。vs Radix / Ark 的状态检测——Headless UI 的「移动端 + 桌面端混合输入」体验最细腻Transition 内置 +
data-closed/data-enter/data-leave:v2 之后所有组件支持transitionprop——不需要 Framer Motion / Motion / Auto Animate 即可写完整 enter / leave 动画。data-closed:opacity-0+data-enter:opacity-100Tailwind 一句话搞定新组件 Checkbox / Input / Select / Textarea:v2 之前必须自己写原生 input 或装第三方库 —— v2 之后Headless UI 自带这套。
<Checkbox indeterminate>/<Input invalid>都内置了 a11y 行为asProp 自由组合:所有组件支持as={Fragment}/as="a"/as={Link}—— 与 Next.js Link / React Router Link 完美组合。vs Radix asChild——as语义更直观、不需要要求子元素 forwardRefRender Props 仍可用(向后兼容):v2 保留 v1 风格的
{({ open, close }) => ...}render prop —— 老项目升级 v2 零成本Portal 默认 + 自动 modal 焦点陷阱:Dialog / Combobox / Listbox / Menu / Popover 等 overlay 类默认 Portal 到 body——z-index 不冲突 + overflow:hidden 不裁剪。Dialog 自动焦点陷阱、自动 body 滚动锁
Tailwind 友好的 className 注入:所有组件接受
className: string | ((state) => string)——支持函数形式根据状态切换 className:tsx<MenuItem className={({ focus }) => (focus ? "bg-blue-100" : "")} >...</MenuItem>Catalyst / Tailwind UI 加持:Catalyst 是 Tailwind 官方付费设计系统、底层完全基于 Headless UI —— 学会 Headless UI = 半个 Catalyst 已经会了。Tailwind UI 的免费组件示例也都用 Headless UI
SSR 完美:Next.js App Router / Remix / TanStack Router / Vite SSR 全部一键集成 —— 无 hydration warning
TypeScript-first:所有组件、props、状态类型完整 —— IDE 智能提示完美
官方文档质量极高 + 实时 Playground:headlessui.com —— 每个组件「Installation」「Basic example」「Styling」「Examples」「Component API」结构清晰、内嵌交互演示
Tailwind Labs 商业化背书:Tailwind 自身是估值 $50亿+ 的开源公司,Headless UI 由专门团队维护 —— bus factor 极稳
包尺寸极小:v2.0 实际打包 ~30KB(vs Radix 单 Primitive ~5-15KB × 多个)—— 整体打包小于 Radix
缺点
- Vue 版严重落后:截至 2026 年 5 月,
@headlessui/vue仍是 v1.7(最后一次更新 ~2024 年)——没有 v2 的 anchor positioning / 没有 Checkbox / 没有 Input / 没有虚拟滚动 / 没有 Field 表单组件。Vue 用户能享受到的 Headless UI = React 用户体验的 ~50%。Tailwind Labs 公开表态过 Vue 版会更新但优先级低于 React。这是 Headless UI 当前最大缺陷 - 组件数量少(16 个 vs Radix 30+):没有 Toast / Tooltip / Hover Card / Alert Dialog / Context Menu / Menubar / Navigation Menu / Accordion / Collapsible / Slider / Progress / Avatar / Aspect Ratio / Scroll Area / Separator 等。Tooltip 是最常用组件之一、Headless UI 没有官方实现(社区需自己写 Popover + hover 逻辑、或装 Radix Tooltip / Floating UI)
- 没有 Toast 是硬伤:通知 / 错误提示 / 操作反馈是几乎所有应用必需 —— Headless UI 缺这个一直被诟病。vs Radix Toast / Sonner / react-hot-toast —— 必须搭配第三方
- 没有 Tooltip 是硬伤:同上,Headless UI 没有 Tooltip 是其和 Radix 最大功能差距。社区方案:
@radix-ui/react-tooltip(最常见)/ TanStack Tooltip - 没有 Accordion / Collapsible:v2 之后仍只有 Disclosure(单项展开),没有手风琴(多项联动)—— 需要自己用 Disclosure 组装
- 没有 Slider / Progress:表单组件只有 Switch / RadioGroup / Checkbox——没有 Slider(数值滑块)/ 没有 Progress(进度条)
- 没有 Context Menu:右键菜单需要自己用 Menu + onContextMenu 组装
- vs Radix UI:Radix 30+ Primitives + a11y 更彻底 + Compound Component 模式更完整;Headless UI 更轻量、Tailwind 集成更紧密、anchor positioning 内置 —— 复杂场景选 Radix、Tailwind 简单场景选 Headless UI
- vs Ark UI:Ark UI(Chakra 团队的 headless 库)—— 基于 Zag 状态机 / 支持 React + Vue + Solid 三框架 / 组件数量更多;Headless UI 更轻量、Tailwind 集成更紧密
- vs shadcn/ui:shadcn/ui 是 Radix + Tailwind + 拷贝代码 组合 —— shadcn 直接提供完整带样式的组件、Headless UI 仍需自己写所有样式。99% 场景下用 shadcn 更快、特别简单的 Tailwind 项目用 Headless UI
asProp 与 TypeScript 类型推导:复杂as用法(如as={MyForwardedComponent})有时候 TS 类型推导比较繁琐——比 RadixasChild类型更复杂- Anchor Positioning 与
position: fixed父容器冲突:少数情况下 anchor 子元素渲染到 portal 外(特别是staticprop + 自定义 wrapper 时)—— 需要手动调 - 没有官方 DataTable / Tree / 富文本:企业级 CRUD 场景完全空白——vs MUI / Ant Design 大量业务组件——Headless UI 定位本来就不是「业务组件库」
- Discord 社区较弱:Tailwind Discord 是综合主题、Headless UI 没有独立社区 —— vs Radix Discord 活跃度更高
- v1 → v2 是 breaking:v2 API 大重写——v1 项目迁移成本不小(详见指南章节)。Vue 用户因为没有 v2 暂时不需要担心
文档地址
Headless UI 官网 | React v2 文档 | Vue v1 文档 | v2 发布博客(2024.5) | Catalyst(Tailwind 官方设计系统) | Tailwind UI
GitHub 地址
tailwindlabs/headlessui(主仓库,27k+ Star) | Releases / Changelog | Issues
学习路径
- 入门:Headless UI 概念(Unstyled /
data-*API / Anchor Positioning / Field 表单)/ React v2 vs Vue v1 选择 /pnpm add @headlessui/react或@headlessui/vue/ 第一个 Menu(含 anchor positioning) / 第一个 Dialog(含 transition + Backdrop) / 第一个 Combobox(含搜索 + 虚拟滚动) / 第一个 Switch + Checkbox / 配合 Tailwind 写 data-* 状态样式 / Transition API(transitionprop +data-closed)/ Next.js App Router 集成 / Vite 集成 / Vue 3 集成(基于 v1) - 指南:核心:16 个组件深度梳理(Overlay:Dialog / Popover / Disclosure;Menu:Menu / Combobox / Listbox / Select;Forms:Checkbox / RadioGroup / Switch / Input / Textarea / Select / Fieldset / Field / Label / Description;Navigation:Tabs;Animation:Transition)/ Anchor Positioning 深度(
anchor="bottom start"/--anchor-gap/--anchor-offset/--anchor-padding/--button-width全部 CSS 变量)/ data- 属性 + Tailwind variant*(data-[hover]:/data-[focus]:/data-[active]:/data-[checked]:/data-[open]:/data-[closed]:/data-[selected]:/data-[disabled]:)/ Render Props vs data- 双模式*(何时用 render prop / 何时用 data-* className) / Controlled vs Uncontrolled / Combobox 虚拟滚动(virtual.options+ render prop)/ Field 表单 ARIA 自动注入 / Portal 与 SSR(portalprop / Next.js App Router 客户端组件)/ Transition 组件 +transitionprop(appear/show/data-closed) /asProp(Fragment / 字符串 / React 组件)/ 与 Tailwind UI / Catalyst 协作 / v1 → v2 迁移指南(renderProp 改名 / data-* 替代 active / Anchor positioning 替代 Floating UI 手动集成)/ Vue v1 vs React v2 差异(Vue 没有 anchor / Checkbox / Input / 虚拟滚动)/ 常见踩坑(SSR portal /as={Fragment}Children.only / 自定义子组件 forwardRef / Transition 不工作) - 参考:API 速查:16 个组件完整清单 / 每个组件的 props 速查(Menu / Dialog / Combobox / Listbox / Popover / Disclosure / Tabs / Switch / RadioGroup / Checkbox / Transition / Field / Fieldset / Input / Select / Textarea) / Anchor 配置完整表(
anchor.to/anchor.gap/anchor.offset/anchor.padding/ CSS 变量列表)/ data- 属性完整表*(每个组件支持的data-*) / Render Props 完整表(每个组件 render prop 暴露的状态) / 键盘快捷键全表 / TypeScript 类型 / Vue v1 API 速查(差异于 React v2 的部分)