标签
轻松创建无障碍、完全可自定义的标签界面,并提供强大的焦点管理和键盘导航支持。
要开始使用,请通过 npm 安装 Headless UI
npm install @headlessui/react
标签是使用 Tab.Group
、Tab.List
、Tab
、Tab.Panels
和 Tab.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> ) }
默认情况下,当用户使用箭头键导航标签时,标签会自动被选中。
如果你希望在用户按下 Enter
或 Space
之前不改变当前标签,请在 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
组件获得焦点时,所有交互都适用。
命令 | 描述 |
左箭头 和 右箭头 | 选择上一个/下一个非禁用的标签。 |
上箭头 和 下箭头 当 | 选择上一个/下一个非禁用的标签。 |
Home 或 PageUp | 选择第一个非禁用的标签。 |
End 或 PageDown | 选择最后一个非禁用的标签。 |
Enter 或 Space 当 | 激活选中的标签。 |
属性 | 默认值 | 描述 |
as | Fragment | 字符串 | 组件
|
defaultIndex | 0 | 数字 默认选中的索引 |
selectedIndex | — | 数字 如果你想将标签组件用作受控组件,则为选中的索引。 |
onChange | — | (index: number) => void 每当活动标签发生变化时调用的函数。 |
vertical | false | 布尔值 当为 true 时, |
manual | false | 布尔值 当为 true 时,用户只能通过首先使用箭头键导航到标签,然后按下 |
渲染道具 | 描述 |
selectedIndex |
当前选中的索引。 |
属性 | 默认值 | 描述 |
as | div | 字符串 | 组件
|
渲染道具 | 描述 |
selectedIndex |
当前选中的索引。 |
属性 | 默认值 | 描述 |
as | button | 字符串 | 组件
|
disabled | false | 布尔值
|
渲染道具 | 描述 |
selected |
|
属性 | 默认值 | 描述 |
as | div | 字符串 | 组件
|
渲染道具 | 描述 |
selectedIndex |
当前选中的索引。 |
属性 | 默认值 | 描述 |
as | div | 字符串 | 组件
|
static | false | 布尔值 元素是否应该忽略选定的索引。 注意: |
unmount | true | 布尔值 元素是否应该根据选定的索引卸载或隐藏。 注意: |
渲染道具 | 描述 |
selected |
|