标签

轻松创建无障碍、完全可自定义的标签界面,并提供强大的焦点管理和键盘导航支持。

要开始使用,请通过 npm 安装 Headless UI

npm install @headlessui/react

标签是使用 Tab.GroupTab.ListTabTab.PanelsTab.Panel 组件构建的。默认情况下,第一个标签被选中,点击任何标签或使用键盘选择它将激活相应的面板。

import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

Headless UI 会跟踪每个组件的许多状态信息,例如当前选中哪个标签选项,弹出窗口是打开还是关闭,或者菜单中哪个项目是当前通过键盘激活的。

但由于这些组件是无头的,并且在开箱即用时完全没有样式,所以你无法在 UI 中看到这些信息,直到你自己提供每个状态所需的样式。

每个组件都通过渲染道具公开其当前状态的信息,你可以使用这些道具有条件地应用不同的样式或渲染不同的内容。

例如,Tab 组件公开了一个 selected 状态,它告诉你标签是否当前被选中。

import { Fragment } from 'react' import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab as={Fragment}>
{({ selected }) => (
/* Use the `selected` state to conditionally style the selected tab. */ <button className={
selected ? 'bg-blue-500 text-white' : 'bg-white text-black'
}
>
Tab 1 </button> )} </Tab> {/* ... */} </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> {/* ... */} </Tab.Panels> </Tab.Group> ) }

有关每个组件的完整渲染道具 API,请参阅组件 API 文档

每个组件还通过 data-headlessui-state 属性公开其当前状态的信息,你可以使用该属性有条件地应用不同的样式。

渲染道具 API中的任何状态为 true 时,它们将作为空格分隔的字符串列在这个属性中,以便你可以使用CSS 属性选择器[attr~=value] 的形式来定位它们。

例如,以下是如何使用一些子 Tab 组件呈现 Tab.Group 组件,当第二个标签被选中时:

<!-- Rendered `Tab.Group` --> <div> <button data-headlessui-state="">Tab 1</button> <button data-headlessui-state="selected">Tab 2</button> <button data-headlessui-state="">Tab 3</button> </div> <div> <div data-headlessui-state="">Content 1</div> <div data-headlessui-state="selected">Content 2</div> <div data-headlessui-state="">Content 3</div> </div>

如果你使用的是Tailwind CSS,你可以使用@headlessui/tailwindcss 插件来使用修饰符(如 ui-open:*)定位此属性。

import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List>
<Tab className="ui-selected:bg-blue-500 ui-selected:text-white ui-not-selected:bg-white ui-not-selected:text-black">
Tab 1 </Tab> {/* ... */} </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> {/* ... */} </Tab.Panels> </Tab.Group> ) }

要禁用标签,请在 Tab 组件上使用 disabled 属性。禁用的标签无法用鼠标选择,并且在使用键盘导航标签列表时也会跳过它们。

import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab>Tab 1</Tab>
<Tab disabled>Tab 2</Tab>
<Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

默认情况下,当用户使用箭头键导航标签时,标签会自动被选中。

如果你希望在用户按下 EnterSpace 之前不改变当前标签,请在 Tab.Group 组件上使用 manual 属性。这在选中标签会执行昂贵的操作,而你不想不必要地执行它时很有用。

import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group manual>
<Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

manual 属性对鼠标交互没有影响 - 标签仍然会在被点击后立即被选中。

如果你将 Tab.List 的样式设置为垂直显示,请使用 vertical 属性来启用使用向上和向下箭头键而不是向左和向右进行导航,以及更新 aria-orientation 属性以用于辅助技术。

import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group vertical>
<Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

要更改默认选中的标签,请在 Tab.Group 组件上使用 defaultIndex={number} 属性。

import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group defaultIndex={1}>
<Tab.List> <Tab>Tab 1</Tab>
{/* Selects this tab by default */}
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel>
{/* Displays this panel by default */}
<Tab.Panel>Content 2</Tab.Panel>
<Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

如果你碰巧提供了超出范围的索引,那么在初始渲染时会选择最后一个非禁用的标签。(例如,在上面的示例中,<Tab.Group defaultIndex={5} 会渲染第三个面板为选中状态。)

要运行一个函数,以便在选中的标签发生更改时运行,请在 Tab.Group 组件上使用 onChange 属性。

import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group
onChange={(index) => {
console.log('Changed selected tab to:', index)
}}
>
<Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

标签组件也可以用作受控组件。为此,请提供 selectedIndex 并自行管理状态。

import { useState } from 'react' import { Tab } from '@headlessui/react' function MyTabs() {
const [selectedIndex, setSelectedIndex] = useState(0)
return (
<Tab.Group selectedIndex={selectedIndex} onChange={setSelectedIndex}>
<Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }

点击 Tab 将选择该标签并显示相应的 Tab.Panel

Tab 组件获得焦点时,所有交互都适用。

命令描述

左箭头右箭头

选择上一个/下一个非禁用的标签。

上箭头下箭头vertical 设置为 true 时

选择上一个/下一个非禁用的标签。

HomePageUp

选择第一个非禁用的标签。

EndPageDown

选择最后一个非禁用的标签。

EnterSpacemanual 设置为 true 时

激活选中的标签。

所有相关的 ARIA 属性都会自动管理。

有关 Tabs 中实现的所有无障碍功能的完整参考,请参阅关于标签的 ARIA 规范

主要的 Tab.Group 组件。

属性默认值描述
asFragment
字符串 | 组件

Tabs 应该渲染成的元素或组件。

defaultIndex0
数字

默认选中的索引

selectedIndex
数字

如果你想将标签组件用作受控组件,则为选中的索引。

onChange
(index: number) => void

每当活动标签发生变化时调用的函数。

verticalfalse
布尔值

当为 true 时,Tab.List 的方向将为 vertical,否则为 horizontal

manualfalse
布尔值

当为 true 时,用户只能通过首先使用箭头键导航到标签,然后按下 EnterSpace 来显示面板。默认情况下,面板会在使用箭头键导航到它们时自动显示。请注意,此属性对鼠标行为没有影响。

渲染道具描述
selectedIndex

数字

当前选中的索引。

属性默认值描述
asdiv
字符串 | 组件

Tab.List 应该渲染成的元素或组件。

渲染道具描述
selectedIndex

数字

当前选中的索引。

属性默认值描述
asbutton
字符串 | 组件

Tab 应该渲染成的元素或组件。

disabledfalse
布尔值

Tab 是否当前被禁用。

渲染道具描述
selected

布尔值

Tab 是否当前被选中。

属性默认值描述
asdiv
字符串 | 组件

Tab.Panels 应该渲染成的元素或组件。

渲染道具描述
selectedIndex

数字

当前选中的索引。

属性默认值描述
asdiv
字符串 | 组件

Tab.Panel 应该渲染成的元素或组件。

staticfalse
布尔值

元素是否应该忽略选定的索引。

注意:staticunmount 不能同时使用。如果尝试这样做,您将收到 TypeScript 错误。

unmounttrue
布尔值

元素是否应该根据选定的索引卸载或隐藏。

注意:staticunmount 不能同时使用。如果尝试这样做,您将收到 TypeScript 错误。

渲染道具描述
selected

布尔值

Tab.Panel 当前是否被选中。

如果您对使用 Headless UI 和 Tailwind CSS 的预先设计的组件示例感兴趣,请查看 **Tailwind UI** - 由我们构建的精美设计和精心制作的组件集合。

这是支持我们对像这样的开源项目的贡献的好方法,使我们能够改进它们并保持良好的维护。