Headless UI
Tailwind Labs 提供的无样式、可访问 UI 组件库,为 React 与 Vue 处理键盘、焦点和复杂交互行为。
项目概述
Headless UI 提供 Dialog、Menu、Combobox、Listbox、Popover、Tabs、Switch 等无视觉预设组件。它负责语义、状态、焦点管理和键盘交互,团队则使用 Tailwind CSS、普通 CSS 或其他方案实现自己的设计系统。
Headless UI 是 Tailwind Labs 维护的一套无样式、可访问 UI 组件,分别通过 @headlessui/react 与 @headlessui/vue 发布。它不提供按钮颜色、圆角、间距或品牌视觉,而是封装 Dialog、Dropdown Menu、Popover、Combobox、Listbox、Tabs、Disclosure、Switch 等控件最容易出错的语义、焦点、键盘导航、选择状态和关闭行为。组件通常拆分为 Button、Panel、Items、Option 等可组合 Parts,并通过 Render Prop、状态属性或 data-* Attribute 暴露交互状态,让开发者用 Tailwind CSS、CSS Module、CSS-in-JS 或普通 CSS 完成外观。当前 React 稳定版为 2.2.10,Vue 稳定版为 1.7.23。
主要特点
Headless UI 聚焦复杂控件的行为与无障碍基础,让团队可以在不继承默认主题的前提下构建设计系统。
完全无样式
组件不附带固定颜色、尺寸、间距和主题,团队可以从零实现品牌视觉而无需覆盖第三方 CSS。
可访问性交互基础
为复杂控件处理 ARIA 语义、键盘导航、关闭行为、选中状态和焦点移动等基础逻辑。
React 与 Vue 支持
官方分别维护 @headlessui/react 和 @headlessui/vue,让两个生态都能使用相近的 Headless Component 思路。
可组合 Parts
DialogPanel、MenuButton、MenuItems、ComboboxInput 等子组件可自由组合 DOM 层级与内容。
Dialog 焦点管理
Dialog 自动使用 Portal、限制焦点留在弹层内、将外部内容设为 Inert,并处理 Escape 和点击外部关闭。
键盘导航
Menu、Listbox、Combobox、Tabs 和 Radio Group 等组件内置方向键、Home/End、Enter、Escape 与字符搜索行为。
状态暴露
通过 Render Prop 和 data-open、data-focus、data-selected、data-disabled 等属性提供可靠的样式钩子。
受控与非受控模式
根据组件提供 Value、DefaultValue、Open 和 OnChange 等模式,与表单或应用状态灵活集成。
自定义渲染元素
使用 as Prop 或 Fragment 改变底层元素,避免为了行为组件添加不需要的包装层。
Transition 支持
组件可暴露进入、离开和开关状态,便于使用 Tailwind Utility 或普通 CSS 编写动画。
表单组件
Checkbox、Combobox、Fieldset、Input、Listbox、Radio Group、Select、Switch 与 Textarea 覆盖常见输入需求。
Tailwind CSS 友好
官方示例直接使用 Utility Class 和 Data Variant,但 Headless UI 本身不强制安装 Tailwind CSS。
TypeScript 类型
官方包提供 TypeScript API 和泛型支持,有助于约束 Value、事件与自定义元素组合。
适用场景
它适合已经拥有视觉规范、使用 React 或 Vue,并希望避免从零实现焦点和键盘交互的产品团队。
自有设计系统
复用稳定的交互与无障碍行为,同时由 Design Token、Tailwind CSS 或 CSS Variables 决定全部视觉。
SaaS 与管理后台
快速构建 Dropdown Menu、Dialog、Combobox、Listbox、Tabs 和 Switch 等高频应用控件。
搜索与命令选择
使用 Combobox 实现自动补全、实体选择、过滤列表和远程搜索,并保留完整键盘操作。
响应式导航
组合 Disclosure、Popover、Menu 和 Transition 构建桌面与移动导航,不继承固定主题。
电商筛选与配置
通过 Listbox、Radio Group、Checkbox 和 Dialog 实现规格、排序、筛选和移动端抽屉。
品牌化营销页面
在 Accordion、Tabs、Popover 和 Modal 中使用高度定制的视觉与动画,同时保留语义和键盘行为。
React/Vue 多产品体系
在交互理念相近的前提下分别使用官方 React 与 Vue 包,但需要维护各自实现和版本差异。
优点与注意事项
技术选型不仅要看能力,也要理解它带来的团队成本。
主要优点
Headless UI 擅长的地方
- 不附带默认主题,不需要大量 CSS Override 就能匹配自有品牌。
- 封装复杂控件的键盘、焦点、Portal 和选择行为,降低重复造轮子风险。
- 组件 Parts 可自由组合,DOM 结构与视觉实现控制权较高。
- 同时支持 React 与 Vue,适合 Tailwind Labs 生态中的不同前端栈。
- Data Attribute 与 Render Prop 让交互状态可以直接映射到样式。
- 与 Tailwind CSS 配合自然,也能使用普通 CSS、CSS Module 或 CSS-in-JS。
- Dialog、Combobox、Menu、Listbox 等覆盖产品应用中最复杂且常见的控件。
- 官方 TypeScript 类型改善编辑器提示和状态 Value 的约束。
- MIT 许可证宽松,适合商业产品、内部设计系统和开源项目。
需要注意
采用前应考虑的问题
必须自行实现布局、主题、动画、Focus Ring、Disabled、Loading、Error 和高对比度状态。
组件提供可靠基础,但错误 Label、缺失说明、错误 DOM 组合或自定义样式仍可能破坏体验。
React 当前为 2.x,Vue 仍为 1.x,组件集合、Props 和文档示例不能直接跨框架照搬。
它不是包含 Data Grid、Date Picker、Rich Text Editor 和图表的全功能企业组件库。
自定义组件必须正确转发 Ref、事件、ARIA 和其他 Props,否则 Headless UI 无法管理焦点和交互。
Dialog 的层级、宽高、滚动容器、Backdrop 和 Z-Index 需要正确设计,尤其要测试长内容与移动键盘。
Open、Value 和 Query 等状态应明确由组件还是业务层管理,避免表单、URL 和本地 State 相互覆盖。
Transition、CSS 动画和条件渲染必须协调,否则可能出现焦点提前丢失、离场动画被截断或不可见内容仍可交互。
交互组件依赖状态、事件和浏览器焦点;在 Next.js 等环境中通常应放入 Client Component 边界。
仓库近期更新频率不高,采用前应核对 Issues、目标框架新版本兼容性和所需组件的修复状态。
Headless UI 面向 Web DOM,不适用于 React Native、Flutter 或原生 iOS/Android View。
应结合 Axe、键盘测试和真实屏幕阅读器验证业务组合,而不是只依赖组件库的默认行为。
快速开始
下面分别展示 React 与 Vue 的安装方式,并用 Dialog、Menu 和状态属性完成可访问交互与自定义样式。
bashnpm install @headlessui/reacttsximport {
Description,
Dialog,
DialogBackdrop,
DialogPanel,
DialogTitle,
} from "@headlessui/react";
import { useState } from "react";
export function DeleteDialog() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>
删除项目
</button>
<Dialog
open={isOpen}
onClose={() => setIsOpen(false)}
className="relative z-50"
>
<DialogBackdrop className="fixed inset-0 bg-black/40" />
<div className="fixed inset-0 flex items-center justify-center p-4">
<DialogPanel className="w-full max-w-md rounded-xl bg-white p-6">
<DialogTitle className="text-lg font-semibold">
确认删除
</DialogTitle>
<Description className="mt-2 text-sm text-zinc-600">
删除后无法恢复。
</Description>
<div className="mt-6 flex justify-end gap-3">
<button onClick={() => setIsOpen(false)}>取消</button>
<button data-autofocus>确认删除</button>
</div>
</DialogPanel>
</div>
</Dialog>
</>
);
}tsximport {
Menu,
MenuButton,
MenuItem,
MenuItems,
} from "@headlessui/react";
export function AccountMenu() {
return (
<Menu>
<MenuButton className="rounded-md border px-3 py-2">
账户
</MenuButton>
<MenuItems
anchor="bottom end"
className="mt-2 w-44 rounded-lg border bg-white p-1 shadow-lg"
>
<MenuItem>
<a
href="/profile"
className="block rounded px-3 py-2 data-focus:bg-zinc-100"
>
个人资料
</a>
</MenuItem>
<MenuItem>
<button className="w-full rounded px-3 py-2 text-left data-focus:bg-zinc-100">
退出登录
</button>
</MenuItem>
</MenuItems>
</Menu>
);
}bashnpm install @headlessui/vuevue<script setup lang="ts">
import { ref } from "vue";
import { Switch } from "@headlessui/vue";
const enabled = ref(false);
</script>
<template>
<Switch
v-model="enabled"
class="group inline-flex h-6 w-11 items-center rounded-full bg-zinc-300 data-checked:bg-indigo-600"
>
<span class="sr-only">启用通知</span>
<span
class="size-4 translate-x-1 rounded-full bg-white transition group-data-checked:translate-x-6"
/>
</Switch>
</template>bashnpm run lint
npm run typecheck
npm test
npm run build
# 使用键盘完成全流程,并测试 VoiceOver、NVDA 或其他屏幕阅读器
# 验证缩放、移动端滚动、高对比度和 Reduced Motion下一步:先确认项目使用 React 还是 Vue,再阅读对应版本文档;视觉样式必须覆盖默认、Hover、Focus、Active、Disabled、Open 和错误状态,并配合键盘与屏幕阅读器测试。
类似项目
这些站内项目覆盖无样式组件原语、源码组件方案、样式工具和 Headless UI 支持的框架;外部项目则提供其他可访问性抽象。
Base UI
无样式、可访问的 React 组件库,以细粒度 Parts、状态属性和灵活组合能力构建设计系统。
查看项目Ark UI
基于 Zag.js 状态机的无样式、可访问组件库,支持 React、Vue、Solid 与 Svelte。
查看项目Radix UI
无样式、可访问且高度可组合的 React UI 原语,为设计系统处理焦点、键盘和复杂交互。
查看项目shadcn/ui
把可访问、可组合的组件源码直接加入项目,由团队完整拥有和定制的 UI 分发平台。
查看项目Tailwind CSS
以实用类为核心的 CSS 框架,快速构建定制化界面。
查看项目React
用于构建 Web 和原生用户界面的组件化 JavaScript 库。
查看项目Vue.js
渐进式 JavaScript 框架,易学易用且拥有优秀的性能表现。
查看项目React Aria
Adobe 提供的可访问 React Hooks 与组件体系,覆盖国际化和跨设备交互。
访问官网Headless UI vs Radix UI
Headless UI 与 Radix UI 都提供无视觉预设的可访问组件,但 Headless UI 强调 React/Vue、较直接的高层组件和 Tailwind CSS 工作流;Radix Primitives 更偏 React 设计系统的低层行为原语与细粒度组合。
| 比较维度 | Headless UI | Radix UI |
|---|---|---|
| 核心定位 | 无样式、高层可访问组件 | 无样式、低层可组合 React 原语 |
| 框架支持 | 官方支持 React 与 Vue | 官方 Primitives 主要面向 React |
| 组件粒度 | 常见控件 API 较直接,Parts 数量适中 | Parts 更细,适合高度定制的设计系统封装 |
| 视觉样式 | 完全无样式,官方示例偏 Tailwind CSS | 完全无样式,可使用任意 CSS 方案 |
| 状态样式 | Render Prop 与 data-* Attribute | 丰富的 data-state、data-side 等 Attribute |
| 弹层定位 | 提供 Anchor 等常用定位能力 | Popover、Tooltip、Menu 等定位和碰撞配置更细 |
| 组件范围 | 覆盖常用表单、Menu、Dialog、Popover 与 Tabs | Primitive 数量更多,包含 Tooltip、Toast、Scroll Area 等 |
| Tailwind 集成 | Tailwind Labs 维护,示例和状态 Variant 配合自然 | 社区常与 Tailwind 和 shadcn/ui 组合 |
| Vue 选择 | 有官方 Vue 包,但版本线独立 | 没有同仓库官方 Vue Primitives |
| 生态关系 | 常直接用于应用或自有 Design System | 是 shadcn/ui 等源码组件体系的重要行为基础 |
| 许可证 | MIT | MIT |
| 更适合 | React/Vue 团队快速构建品牌化常用控件 | React 团队构建细粒度、复杂交互的设计系统 |
如果团队使用 React 或 Vue,希望用较直接的组件 API 快速实现自有视觉,并与 Tailwind CSS 紧密配合,Headless UI 通常更省步骤;如果只面向 React,需要更丰富的 Primitive、精细弹层控制,或计划基于 shadcn/ui 构建设计系统,Radix UI 往往更合适。最终应以所需组件清单、框架版本、键盘交互和移动端行为制作验证原型。
资料核验
版本、维护信息与本页采用的官方资料来源。
npm 官方元数据核验的 @headlessui/react 稳定版为 2.2.10,@headlessui/vue 稳定版为 1.7.23,两者均采用 MIT 许可证。官方文档确认组件完全无样式并聚焦可访问交互。官方仓库未归档,最近可见提交日期为 2026 年 4 月 13 日,因此标记为稳定维护。
官方仓库未归档,核验时最近可见的代码活动日期为 2026 年 4 月 13 日。项目更新频率较低但仍有维护迹象,因此标记为稳定维护,而不是活跃更新。