揭露
用於建立自訂 UI 的簡單、便利的基礎,可用於顯示和隱藏內容,例如可切換的手風琴面板。
要開始請透過 npm 安裝 Headless 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>
)
}
Headless UI 會追蹤每個元件的大量狀態,例如目前選取哪個方塊選單選項、快顯功能表是開啟還是關閉、或揭露資訊的哪個項目目前是以鍵盤做為焦點。
但是,因為這些元件是無頭的,而且在剛推出時完全沒有造型,所以在你自行提供每種狀態所需的造型前,你無法在使用者介面看到這些資訊。
造型 Headless 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` 之後接收焦點,但您可以將參考傳遞至 `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` 屬性,可讓元件渲染為不同元件或您自己的自訂元件,但務必確保您的自訂元件會 轉送參考,這樣無外觀 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當一個 | 切換面板 |
屬性 | 預設 | 說明 |
as | Fragment | 字串 | 元件 元素或揭露應呈現為。 |
defaultOpen | false | 布林值
|
資料屬性 | 渲染屬性 | 說明 |
data-open | open |
揭露是否開啟。 |
— | close |
關閉揭露並重新聚焦 |
屬性 | 預設 | 說明 |
as | button | 字串 | 元件 元素或揭露按鈕應呈現為。 |
autoFocus | false | 布林值 當一開始渲染時是否揭露按鈕應獲得焦點。 |
資料屬性 | 渲染屬性 | 說明 |
data-open | open |
當一開始渲染時是否揭露開啟時。 |
data-focus | focus |
當一開始渲染時是否揭露按鈕有焦點時。 |
data-hover | hover |
當一開始渲染時是否揭露按鈕有滑鼠時。 |
data-active | active |
當一開始渲染時是否揭露按鈕處於 active 或已按下狀態時。 |
data-autofocus | autofocus |
|
屬性 | 預設 | 說明 |
as | div | 字串 | 元件 元素或揭露面板應呈現為。 |
transition | false | 布林值 元素是否應呈現轉場屬性,例如 |
static | false | 布林值 元素是否應忽略內部管理的開啟/關閉狀態。 |
unmount | true | 布林值 元素是否應根據開啟/關閉狀態卸載或隱藏。 |
資料屬性 | 渲染屬性 | 說明 |
data-open | open |
當一開始渲染時是否揭露開啟時。 |
— | close |
關閉揭露並重新聚焦 |
屬性 | 預設 | 說明 |
as | button | 字串 | 元件 元素或Close按鈕應呈現為。 |
如果您有興趣預先設計 Tailwind CSS 揭露組件範例 使用 Headless UI,檢視Tailwind UI — 我們建立的精選精緻設計和專家級製作組件。
這是一個支援我們在開放原始碼專案,例如這個專案,中所做工作的絕佳方式,使我們能夠改進並保持這些專案的良好維護。