披露
一个简单、可访问的基础,用于构建自定义 UI,显示和隐藏内容,例如可切换的手风琴面板。
要开始,请通过 npm 安装 Headless UI
npm install @headlessui/react
披露使用 Disclosure
、Disclosure.Button
和 Disclosure.Panel
组件构建。
按钮将自动在单击时打开/关闭面板,所有组件都将接收适当的 aria-* 相关属性,例如 aria-expanded
和 aria-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> ) }
这在使用披露来执行诸如包含链接的移动菜单之类的操作时特别有用,您希望在导航到下一页时关闭披露。
或者,Disclosure
和 Disclosure.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>
<Transitionenter="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 entireteam. </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. */}<Transitionshow={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 yourentire team.</Disclosure.Panel></Transition> </> )} </Disclosure> ) }
由于它们是无状态的,因此 Headless UI 组件还可以很好地与 React 生态系统中的其他动画库(如Framer Motion 和React 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 的面板打开和关闭。
命令 | 描述 |
Enter 或 Space 当 | 切换面板 |
道具 | 默认值 | 描述 |
as | Fragment | 字符串 | 组件
|
defaultOpen | false | 布尔值
|
渲染道具 | 描述 |
open |
披露是否打开。 |
close |
关闭披露并重新获取 |
道具 | 默认值 | 描述 |
as | button | 字符串 | 组件
|
渲染道具 | 描述 |
open |
披露是否打开。 |
道具 | 默认值 | 描述 |
as | div | 字符串 | 组件
|
static | false | 布尔值 元素是否应忽略内部管理的打开/关闭状态。 注意: |
unmount | true | 布尔值 元素是否应根据打开/关闭状态卸载或隐藏。 注意: |
渲染道具 | 描述 |
open |
披露是否打开。 |
close |
关闭披露并重新获取 |