揭露

用於建立自訂 UI 的簡單、便利的基礎,可用於顯示和隱藏內容,例如可切換的手風琴面板。

要開始請透過 npm 安裝 Headless UI

npm install @headlessui/react

揭露資訊是使用 DisclosureDisclosureButtonDisclosurePanel 元件建立的。

這個按鈕在點擊時將自動開啟/關閉面板,而且所有元件都將接收適當的 aria-* 相關屬性,例如 aria-expandedaria-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 MotionReact 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當一個 DisclosureButton 被聚焦時。

切換面板

主要揭露元件。

屬性預設說明
asFragment
字串 | 元件

元素或揭露應呈現為。

defaultOpenfalse
布林值

Disclosure 元件是否應預設開啟。

資料屬性渲染屬性說明
data-openopen

布林值

揭露是否開啟。

close

(ref) => void

關閉揭露並重新聚焦 DisclosureButton。可選擇傳入 **ref** 或 **HTMLElement** 以聚焦該元素。

切換揭露的觸發元件。

屬性預設說明
asbutton
字串 | 元件

元素或揭露按鈕應呈現為。

autoFocusfalse
布林值

當一開始渲染時是否揭露按鈕應獲得焦點。

資料屬性渲染屬性說明
data-openopen

布林值

當一開始渲染時是否揭露開啟時。

data-focusfocus

布林值

當一開始渲染時是否揭露按鈕有焦點時。

data-hoverhover

布林值

當一開始渲染時是否揭露按鈕有滑鼠時。

data-activeactive

布林值

當一開始渲染時是否揭露按鈕處於 active 或已按下狀態時。

data-autofocusautofocus

布林值

autoFocus 屬性是否已設定為 true

此元件包含揭露的內容。

屬性預設說明
asdiv
字串 | 元件

元素或揭露面板應呈現為。

transitionfalse
布林值

元素是否應呈現轉場屬性,例如 data-closed data-enterdata-leave

staticfalse
布林值

元素是否應忽略內部管理的開啟/關閉狀態。

unmounttrue
布林值

元素是否應根據開啟/關閉狀態卸載或隱藏。

資料屬性渲染屬性說明
data-openopen

布林值

當一開始渲染時是否揭露開啟時。

close

(ref) => void

關閉揭露並重新聚焦 DisclosureButton。可選擇傳入 **ref** 或 **HTMLElement** 以聚焦該元素。

點選此按鈕將關閉最近的 DisclosurePanel 祖先。或者,使用 useClose 掛勾以強制關閉公告面板。

屬性預設說明
asbutton
字串 | 元件

元素或Close按鈕應呈現為。

如果您有興趣預先設計 Tailwind CSS 揭露組件範例 使用 Headless UI,檢視Tailwind UI — 我們建立的精選精緻設計和專家級製作組件。

這是一個支援我們在開放原始碼專案,例如這個專案,中所做工作的絕佳方式,使我們能夠改進並保持這些專案的良好維護。