公开
一个简单、可访问的构建自定义 UI 的基础,用于显示和隐藏内容,例如可切换的手风琴面板。
要开始使用,请通过 npm 安装无头 UI
npm install @headlessui/react
公开使用 `Disclosure`、`DisclosureButton` 和 `DisclosurePanel` 组件构建。
按钮将在点击时自动打开/关闭面板,所有组件将接收相应的 `aria-*` 相关属性,例如 `aria-expanded` 和 `aria-controls`。
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
function Example() {
return (
<Disclosure>
<DisclosureButton className="py-2">Is team pricing available?</DisclosureButton>
<DisclosurePanel className="text-gray-500">
Yes! You can purchase a license that you can share with your entire team.
</DisclosurePanel>
</Disclosure>
)
}
无头 UI 会跟踪每个组件的很多状态,例如当前选择了哪个列表框选项,弹出框是打开还是关闭,或者在公开中哪个项目当前通过键盘获得焦点。
但由于组件是无头且开箱即用完全无样式的,因此您无法在 UI 中看到此信息,除非您自己提供想要为每个状态提供的样式。
对无头 UI 组件的不同状态进行样式设置的最简单方法是使用每个组件公开的 `data-*` 属性。
例如,`DisclosureButton` 组件公开了 `data-open` 属性,它告诉您公开当前是否打开。
<!-- Rendered `Disclosure` -->
<button data-open>Do you offer technical support?</button>
<div data-open>No</div>
使用 CSS 属性选择器 根据这些数据属性的存在有条件地应用样式。如果您使用的是 Tailwind CSS,则 数据属性修饰符 使此操作变得容易
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
function Example() {
return (
<Disclosure>
<DisclosureButton className="group flex items-center gap-2">
Do you offer technical support?
<ChevronDownIcon className="w-5 group-data-[open]:rotate-180" /> </DisclosureButton>
<DisclosurePanel>No</DisclosurePanel>
</Disclosure>
)
}
请参阅 组件 API 以了解所有可用数据属性的列表。
每个组件还通过 渲染道具 公开其当前状态的信息,您可以使用它有条件地应用不同的样式或渲染不同的内容。
例如,`DisclosureButton` 组件公开了 `open` 状态,它告诉您公开当前是否打开。
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import clsx from 'clsx'
function Example() {
return (
<Disclosure>
{({ open }) => ( <>
<DisclosureButton className="flex items-center gap-2">
Do you offer technical support?
<ChevronDownIcon className={clsx('w-5', open && 'rotate-180')} /> </DisclosureButton>
<DisclosurePanel>No</DisclosurePanel>
</>
)} </Disclosure>
)
}
请参阅 组件 API 以了解所有可用渲染道具的列表。
要动画公开面板的打开和关闭,请将 `transition` 道具添加到 `DisclosurePanel` 组件,然后使用 CSS 对过渡的不同阶段进行样式设置
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
function Example() {
return (
<Disclosure as="div" className="w-full max-w-md">
<DisclosureButton className="w-full border-b pb-2 text-left">Is team pricing available?</DisclosureButton>
<div className="overflow-hidden py-2">
<DisclosurePanel
transition className="origin-top transition duration-200 ease-out data-[closed]:-translate-y-6 data-[closed]:opacity-0" >
Yes! You can purchase a license that you can share with your entire team.
</DisclosurePanel>
</div>
</Disclosure>
)
}
`transition` 道具在内部以与 `Transition` 组件完全相同的方式实现。请参阅 过渡文档 以了解更多信息。
无头 UI 还与 React 生态系统中的其他动画库(如 Framer Motion 和 React Spring)很好地组合。您只需要将一些状态暴露给这些库。
例如,要使用 Framer Motion 对菜单进行动画处理,请将 `static` 道具添加到 `DisclosurePanel` 组件,然后根据 `open` 渲染道具有条件地渲染它
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import { AnimatePresence, easeOut, motion } from 'framer-motion'
import { Fragment } from 'react'
function Example() {
return (
<Disclosure as="div" className="w-full max-w-md"> {({ open }) => (
<>
<DisclosureButton className="w-full border-b pb-2 text-left">Is team pricing available?</DisclosureButton>
<div className="overflow-hidden py-2">
<AnimatePresence>
{open && (
<DisclosurePanel static as={Fragment}> <motion.div
initial={{ opacity: 0, y: -24 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -24 }}
transition={{ duration: 0.2, ease: easeOut }}
className="origin-top"
>
Yes! You can purchase a license that you can share with your entire team.
</motion.div>
</DisclosurePanel>
)}
</AnimatePresence>
</div>
</> )}
</Disclosure>
)
}
要手动关闭面板子级单击时的公开,请将该子级渲染为 `CloseButton`。您可以使用 `as` 道具自定义正在渲染的元素。
import { CloseButton, Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import MyLink from './MyLink'
function Example() {
return (
<Disclosure>
<DisclosureButton>Open mobile menu</DisclosureButton>
<DisclosurePanel>
<CloseButton as={MyLink} href="/home"> Home </CloseButton> </DisclosurePanel>
</Disclosure>
)
}
这在将公开用于移动菜单(其中包含链接,您希望在导航到下一页时公开关闭)时特别有用。
`Disclosure` 和 `DisclosurePanel` 还公开了 `close` 渲染道具,您可以使用它强制关闭面板,例如在运行异步操作后
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
function Example() {
return (
<Disclosure>
<DisclosureButton>Terms</DisclosureButton>
<DisclosurePanel>
{({ close }) => ( <button onClick={async () => { await fetch('/accept-terms', { method: 'POST' }) close() }} > Read and accept </button> )} </DisclosurePanel>
</Disclosure>
)
}
默认情况下,`DisclosureButton` 会在调用 `close` 后接收焦点,但您可以通过将 ref 传递到 `close(ref)` 中来更改它。
最后,无头 UI 还提供了一个 `useClose` 钩子,当您无法轻松访问 `close` 渲染道具(例如在嵌套组件中)时,可以使用它来强制关闭最近的公开祖先
import { Disclosure, DisclosureButton, DisclosurePanel, useClose } from '@headlessui/react'
function MySearchForm() {
let close = useClose()
return (
<form
onSubmit={(event) => {
event.preventDefault()
/* Perform search... */
close() }}
>
<input type="search" />
<button type="submit">Submit</button>
</form>
)
}
function Example() {
return (
<Disclosure>
<DisclosureButton>Filters</DisclosureButton>
<DisclosurePanel>
<MySearchForm />
{/* ... */}
</DisclosurePanel>
</Disclosure>
)
}
`useClose` 钩子必须在嵌套在 `Disclosure` 中的组件中使用,否则它将无法正常工作。
`Disclosure` 及其子组件分别渲染一个适合该组件的默认元素:`Button` 渲染一个 `<button>`,`Panel` 渲染一个 `<div>`。相反,根 `Disclosure` 组件不渲染元素,而是默认直接渲染其子级。
使用 `as` 道具将组件渲染为不同的元素或您自己的自定义组件,确保您的自定义组件 转发 refs,以便无头 UI 可以正确地连接一切。
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import { forwardRef } from 'react'
let MyCustomButton = forwardRef(function (props, ref) { return <button className="..." ref={ref} {...props} />})
function Example() {
return (
<Disclosure as="div"> <DisclosureButton as={MyCustomButton}>What languages do you support?</DisclosureButton> <DisclosurePanel as="ul"> <li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</DisclosurePanel>
</Disclosure>
)
}
命令 | 描述 |
Enter 或 Space当 `DisclosureButton` 获得焦点时。 | 切换面板 |
道具 | 默认值 | 描述 |
as | Fragment | String | Component 公开应渲染为的元素或组件。公开应该渲染为。 |
defaultOpen | false | Boolean `Disclosure` 组件默认情况下是否应该打开。 |
数据属性 | 渲染道具 | 描述 |
data-open | open |
公开是否打开。 |
— | close |
关闭公开并重新聚焦 `DisclosureButton`。可以选择传递一个ref或HTMLElement来改为聚焦该元素。 |
道具 | 默认值 | 描述 |
as | button | String | Component 公开应渲染为的元素或组件。公开按钮应该渲染为。 |
autoFocus | false | Boolean 是否公开按钮在首次渲染时应接收焦点。 |
数据属性 | 渲染道具 | 描述 |
data-open | open |
是否公开是打开的。 |
data-focus | focus |
是否公开按钮获得焦点。 |
data-hover | hover |
是否公开按钮悬停。 |
data-active | active |
是否公开按钮处于活动或按下状态。 |
data-autofocus | autofocus |
`autoFocus` 道具是否设置为 `true`。 |
道具 | 默认值 | 描述 |
as | div | String | Component 公开应渲染为的元素或组件。公开面板应该渲染为。 |
transition | false | Boolean 元素是否应渲染过渡属性,例如 `data-closed`、 `data-enter` 和 `data-leave`。 |
static | false | Boolean 元素是否应忽略内部管理的打开/关闭状态。 |
unmount | true | Boolean 元素是否应根据打开/关闭状态卸载或隐藏。 |
数据属性 | 渲染道具 | 描述 |
data-open | open |
是否公开是打开的。 |
— | close |
关闭公开并重新聚焦 `DisclosureButton`。可以选择传递一个ref或HTMLElement来改为聚焦该元素。 |
道具 | 默认值 | 描述 |
as | button | String | Component 公开应渲染为的元素或组件。关闭按钮应该渲染为。 |
如果您有兴趣使用 Headless UI 预先设计的Tailwind CSS 公开组件示例, 请查看Tailwind UI - 我们精心设计的精美组件集合。
这是支持我们对像这样的开源项目工作的绝佳方式,并使我们能够改进它们并保持良好的维护。