披露

一个简单、可访问的基础,用于构建自定义 UI,显示和隐藏内容,例如可切换的手风琴面板。

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

npm install @headlessui/react

披露使用 DisclosureDisclosure.ButtonDisclosure.Panel 组件构建。

按钮将自动在单击时打开/关闭面板,所有组件都将接收适当的 aria-* 相关属性,例如 aria-expandedaria-controls

import { Disclosure } from '@headlessui/react' function MyDisclosure() { return ( <Disclosure> <Disclosure.Button className="py-2"> Is team pricing available? </Disclosure.Button> <Disclosure.Panel className="text-gray-500"> Yes! You can purchase a license that you can share with your entire team. </Disclosure.Panel> </Disclosure> ) }

Headless UI 会跟踪有关每个组件的大量状态,例如当前选择的哪个列表框选项,弹出窗口是打开还是关闭,或者通过键盘当前活动的是哪个披露项目。

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

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

例如,Disclosure 组件公开了一个 open 状态,它告诉您披露当前是否打开。

import { Disclosure } from '@headlessui/react' import { ChevronRightIcon } from '@heroicons/react/20/solid' function MyDisclosure() { return ( <Disclosure>
{({ open }) => (
/* Use the `open` state to conditionally change the direction of an icon. */ <> <Disclosure.Button> Do you offer technical support?
<ChevronRightIcon className={open ? 'rotate-90 transform' : ''} />
</Disclosure.Button> <Disclosure.Panel>No</Disclosure.Panel> </> )} </Disclosure> ) }

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

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

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

例如,以下是 Disclosure 组件在披露打开时呈现的内容

<!-- Rendered `Disclosure` --> <div data-headlessui-state="open"> <button data-headlessui-state="open">Do you offer technical support?</button> <div data-headlessui-state="open">No</div> </div>

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

import { Disclosure } from '@headlessui/react' import { ChevronRightIcon } from '@heroicons/react/20/solid' function MyDisclosure() { return ( <Disclosure> <Disclosure.Button> Do you offer technical support?
<ChevronRightIcon className="ui-open:rotate-90 ui-open:transform" />
</Disclosure.Button> <Disclosure.Panel>No</Disclosure.Panel> </Disclosure> ) }

要在单击面板的子级时手动关闭披露,请将该子级渲染为 Disclosure.Button。您可以使用 as 属性来自定义正在渲染的元素。

import { Disclosure } from '@headlessui/react' import MyLink from './MyLink' function MyDisclosure() { return ( <Disclosure> <Disclosure.Button>Open mobile menu</Disclosure.Button> <Disclosure.Panel>
<Disclosure.Button as={MyLink} href="/home">
Home
</Disclosure.Button>
{/* ... */} </Disclosure.Panel> </Disclosure> ) }

这在使用披露来执行诸如包含链接的移动菜单之类的操作时特别有用,您希望在导航到下一页时关闭披露。

或者,DisclosureDisclosure.Panel 公开了一个 close() 渲染道具,您可以使用它来强制关闭面板,例如在运行异步操作后。

import { Disclosure } from '@headlessui/react' function MyDisclosure() { return ( <Disclosure> <Disclosure.Button>Terms</Disclosure.Button> <Disclosure.Panel>
{({ close }) => (
<button onClick={async () => {
await fetch('/accept-terms', { method: 'POST' })
close()
}}
>
Read and accept </button> )} </Disclosure.Panel> </Disclosure> ) }

默认情况下,Disclosure.Button 会在调用 close() 后收到焦点,但您可以通过将 ref 传递到 close(ref) 中来更改此行为。

要为菜单面板的打开/关闭设置动画,请使用提供的 Transition 组件。您需要做的就是将 Disclosure.Panel 包装在 <Transition> 中,过渡将自动应用。

import { Disclosure, Transition } from '@headlessui/react' function MyDisclosure() { return ( <Disclosure> <Disclosure.Button>Is team pricing available?</Disclosure.Button>
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Disclosure.Panel>
Yes! You can purchase a license that you can share with your entire
team. </Disclosure.Panel> </Transition> </Disclosure> ) }

默认情况下,我们内置的 Transition 组件会自动与 Disclosure 组件通信以处理打开/关闭状态。但是,如果您需要更多地控制此行为,您可以显式地控制它

import { Disclosure, Transition } from '@headlessui/react' function MyDisclosure() { return ( <Disclosure>
{({ open }) => (
<>
<Disclosure.Button>Is team pricing available?</Disclosure.Button> {/* Use the `Transition` + `open` render prop argument to add transitions. */}
<Transition
show={open}
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
{/* Don't forget to add `static` to your `Disclosure.Panel`! */}
<Disclosure.Panel static>
Yes! You can purchase a license that you can share with your
entire team.
</Disclosure.Panel>
</Transition> </> )} </Disclosure> ) }

由于它们是无状态的,因此 Headless UI 组件还可以很好地与 React 生态系统中的其他动画库(如Framer MotionReact Spring)配合使用。

Disclosure 及其子组件都渲染一个对该组件来说明智的默认元素:Button 渲染一个 <button>Panel 渲染一个 <div>。相比之下,根 Disclosure 组件不会渲染元素,而是默认直接渲染其子级。

使用 as 属性将组件渲染为不同的元素或作为您自己的自定义组件,确保您的自定义组件转发 ref,以便 Headless UI 可以正确地连接它们。

import { forwardRef, Fragment } from 'react' import { Disclosure } from '@headlessui/react'
let MyCustomButton = forwardRef(function (props, ref) {
return <button className="..." ref={ref} {...props} />
})
function MyDisclosure() { return (
<Disclosure as="div">
<Disclosure.Button as={MyCustomButton}>
What languages do you support? </Disclosure.Button>
<Disclosure.Panel as="ul">
<li>HTML</li> <li>CSS</li> <li>JavaScript</li> </Disclosure.Panel> </Disclosure> ) }

单击 Disclosure.Button 会切换 Disclosure 的面板打开和关闭。

命令描述

EnterSpaceDisclosure.Button 获得焦点时。

切换面板

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

主要的 Disclosure 组件。

道具默认值描述
asFragment
字符串 | 组件

Disclosure 应渲染成的元素或组件。

defaultOpenfalse
布尔值

Disclosure 组件是否应默认打开。

渲染道具描述
open

布尔值

披露是否打开。

close

(ref?: ref | HTMLElement) => void

关闭披露并重新获取 Disclosure.Button 的焦点。可以选择传递一个refHTMLElement 来改为获取该元素的焦点。

切换 Disclosure 的触发器组件。

道具默认值描述
asbutton
字符串 | 组件

Disclosure.Button 应渲染成的元素或组件。

渲染道具描述
open

布尔值

披露是否打开。

此组件包含披露的内容。

道具默认值描述
asdiv
字符串 | 组件

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

staticfalse
布尔值

元素是否应忽略内部管理的打开/关闭状态。

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

unmounttrue
布尔值

元素是否应根据打开/关闭状态卸载或隐藏。

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

渲染道具描述
open

布尔值

披露是否打开。

close

(ref?: ref | HTMLElement) => void

关闭披露并重新获取 Disclosure.Button 的焦点。可以选择传递一个refHTMLElement 来改为获取该元素的焦点。

如果您有兴趣使用 Headless UI 和 Tailwind CSS 预先设计的组件示例,请查看Tailwind UI——我们精心设计和制作的精美组件集。

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