Popover
Popoverは、ナビゲーションメニュー、モバイルメニュー、フライアウトメニューなど、任意のコンテンツを含むフローティングパネルに最適です。
開始するには、npm経由でHeadless UIをインストールします。
このライブラリはVue 3のみサポートしていますのでご注意ください。
npm install @headlessui/vue
Popoverは、Popover
、PopoverButton
、PopoverPanel
コンポーネントを使用して構築されています。
PopoverButton
をクリックすると、PopoverPanel
が自動的に開閉します。パネルが開いている場合、そのコンテンツの外側をクリックするか、Escapeキーを押すか、タブキーでパネルから離れると、Popoverが閉じます。
<template> <Popover class="relative"> <PopoverButton>Solutions</PopoverButton> <PopoverPanel class="absolute z-10"> <div class="grid grid-cols-2"> <a href="/analytics">Analytics</a> <a href="/engagement">Engagement</a> <a href="/security">Security</a> <a href="/integrations">Integrations</a> </div> <img src="/solutions.jpg" alt="" /> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' </script>
これらのコンポーネントは完全にスタイルが設定されていないため、Popover
のスタイル設定方法はユーザー次第です。この例では、PopoverPanel
に絶対位置付けを使用し、PopoverButton
の近くに配置し、通常のドキュメントの流れを妨げないようにしています。
Headless UIは、現在選択されているリストボックスのオプション、Popoverが開いているか閉じているか、キーボードで現在アクティブになっているPopover内のアイテムなど、各コンポーネントに関する多くの状態を追跡します。
しかし、コンポーネントはヘッドレスであり、すぐに使える状態で完全にスタイルが設定されていないため、各状態に必要なスタイルを自分で提供するまで、UIでこの情報は見えません。
各コンポーネントは、スロットプロップを介して現在の状態に関する情報を公開し、これを使用して条件付きで異なるスタイルを適用したり、異なるコンテンツをレンダリングしたりできます。
たとえば、Popover
コンポーネントはopen
状態を公開し、Popoverが現在開いているかどうかを示します。
<template>
<Popover v-slot="{ open }"><!-- Use the `open` state to conditionally change the direction of the chevron icon. --> <PopoverButton> Solutions<ChevronDownIcon :class="{ 'rotate-180 transform': open }" /></PopoverButton> <PopoverPanel> <a href="/insights">Insights</a> <a href="/automations">Automations</a> <a href="/reports">Reports</a> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' import { ChevronDownIcon } from '@heroicons/vue/20/solid' </script>
使用可能なすべてのスロットプロップの完全なリストについては、コンポーネントAPIドキュメントを参照してください。
各コンポーネントは、条件付きで異なるスタイルを適用するために使用できるdata-headlessui-state
属性を介して現在の状態に関する情報を公開します。
スロットプロップAPIのいずれかの状態がtrue
の場合、それらはスペースで区切られた文字列としてこの属性にリストされます。これにより、[attr~=value]
形式のCSS属性セレクターでターゲットにできます。
たとえば、Popoverが開いている場合、Popover
コンポーネントは次のようにレンダリングされます。
<!-- Rendered `Popover` --> <div data-headlessui-state="open"> <button data-headlessui-state="open">Solutions</button> <div data-headlessui-state="open"> <a href="/insights">Insights</a> <a href="/automations">Automations</a> <a href="/reports">Reports</a> </div> </div>
Tailwind CSSを使用している場合、@headlessui/tailwindcssプラグインを使用して、ui-open:*
のような修飾子でこの属性をターゲットにできます。
<template> <Popover> <PopoverButton> Solutions
<ChevronDownIcon class="ui-open:rotate-180 ui-open:transform" /></PopoverButton> <PopoverPanel> <a href="/insights">Insights</a> <a href="/automations">Automations</a> <a href="/reports">Reports</a> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' import { ChevronDownIcon } from '@heroicons/vue/20/solid' </script>
デフォルトでは、PopoverPanel
は、Popover
コンポーネント自体内で追跡される内部のopen状態に基づいて自動的に表示/非表示されます。
<template> <Popover> <PopoverButton>Solutions</PopoverButton> <!-- By default, the `PopoverPanel` will automatically show/hide when the `PopoverButton` is pressed. --> <PopoverPanel> <!-- ... --> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' </script>
自分で処理したい場合(たとえば、何らかの理由で追加のラッパー要素を追加する必要がある場合)、PopoverPanel
にstatic
プロップを渡して常にレンダリングするように指示し、open
スロットプロップを使用してパネルの表示/非表示を自分で制御できます。
<template>
<Popover v-slot="{ open }"><PopoverButton>Solutions</PopoverButton> <div v-if="open"><!--Using the `static` prop, the `PopoverPanel` is alwaysrendered and the `open` state is ignored.--> <PopoverPanel static> <!-- ... --> </PopoverPanel> </div> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' </script>
Popoverにはフォームコントロールのようなインタラクティブなコンテンツが含まれる可能性があるため、Menu
コンポーネントのように、内部の何かをクリックしたときに自動的に閉じることはできません。
パネルの子をクリックしたときにPopoverを手動で閉じたい場合は、その子をPopoverButton
としてレンダリングします。:as
プロップを使用して、レンダリングされる要素をカスタマイズできます。
<template> <Popover> <PopoverButton>Solutions</PopoverButton> <PopoverPanel>
<PopoverButton :as="MyLink" href="/insights">Insights</PopoverButton><!-- ... --> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' import MyLink from './MyLink' </script>
あるいは、非同期アクションを実行した後に命令的にパネルを閉じたい場合は、Popover
とPopoverPanel
はclose()
スロットプロップを公開します。
<template> <Popover> <PopoverButton>Solutions</PopoverButton>
<PopoverPanel v-slot="{ close }"><button @click="accept(close)">Read and accept</button></PopoverPanel></Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'async function accept(close) {await fetch('/accept-terms', { method: 'POST' })close()}</script>
デフォルトでは、close()
を呼び出した後、PopoverButton
がフォーカスを受け取りますが、refをclose(ref)
に渡すことで変更できます。
Popoverを開くたびにアプリケーションUIの上に背景をスタイル設定したい場合は、PopoverOverlay
コンポーネントを使用します。
<template> <Popover v-slot="{ open }"> <PopoverButton>Solutions</PopoverButton>
<PopoverOverlay class="fixed inset-0 bg-black opacity-30" /><PopoverPanel> <!-- ... --> </PopoverPanel> </Popover> </template> <script setup> import { Popover, PopoverOverlay, PopoverButton, PopoverPanel, } from '@headlessui/vue' </script>
この例では、パネルのコンテンツを覆わないように、DOM内でPopoverOverlay
をPanel
の前に配置しています。
しかし、他のすべてのコンポーネントと同様に、PopoverOverlay
は完全にヘッドレスなので、スタイル設定方法はユーザー次第です。
Popoverのパネルの開閉をアニメーション化するには、Vueの組み込み<transition>
要素を使用できます。<transition>
でPopoverPanel
をラップするだけで、トランジションが自動的に適用されます。
<template> <Popover> <PopoverButton>Solutions</PopoverButton> <!-- Use the built-in `transition` component to add transitions. -->
<transitionenter-active-class="transition duration-200 ease-out"enter-from-class="translate-y-1 opacity-0"enter-to-class="translate-y-0 opacity-100"leave-active-class="transition duration-150 ease-in"leave-from-class="translate-y-0 opacity-100"leave-to-class="translate-y-1 opacity-0"><PopoverPanel> <!-- ... --> </PopoverPanel> </transition> </Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' </script>
Popoverの異なる子要素に対して複数のトランジションを調整したい場合は、Headless UIに含まれるTransitionコンポーネントを確認してください。
複数の関連するPopoverをレンダリングする場合(たとえば、サイトのヘッダーナビゲーションなど)、PopoverGroup
コンポーネントを使用します。これにより、ユーザーがグループ内のPopover間をタブで移動している間はパネルが開いたままになり、ユーザーがグループの外側をタブで移動すると開いているパネルが閉じます。
<template>
<PopoverGroup><Popover> <PopoverButton>Product</PopoverButton> <PopoverPanel> <!-- ... --> </PopoverPanel> </Popover> <Popover> <PopoverButton>Solutions</PopoverButton> <PopoverPanel> <!-- ... --> </PopoverPanel> </Popover></PopoverGroup></template> <script setup> import { PopoverGroup, Popover, PopoverButton, PopoverPanel, } from '@headlessui/vue' </script>
Popover
とそのサブコンポーネントはそれぞれ、そのコンポーネントに適したデフォルトの要素をレンダリングします。Popover
、Overlay
、Panel
、Group
コンポーネントはすべて<div>
をレンダリングし、Button
コンポーネントは<button>
をレンダリングします。
これは、すべてのコンポーネントに存在するas
プロップを使用して簡単に変更できます。
<template> <!-- Render a `nav` instead of a `div` -->
<Popover as="nav"><PopoverButton>Solutions</PopoverButton> <!-- Render a `form` instead of a `div` --><PopoverPanel as="form"><!-- ... --></PopoverPanel></Popover> </template> <script setup> import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue' </script>
開いているパネルでTabキーを押すと、パネルのコンテンツ内の最初のフォーカス可能な要素にフォーカスが移動します。PopoverGroup
を使用している場合、Tabキーは開いているパネルのコンテンツの最後から次のPopoverのボタンに移動します。
PopoverButton
をクリックすると、パネルが開閉します。開いているパネルの外側をクリックすると、そのパネルが閉じます。
コマンド | 説明 |
EnterまたはSpaceを | パネルの切り替え |
Esc | 開いているPopoverをすべて閉じます |
Tab | 開いているパネルのコンテンツ間を移動します 開いているパネルからタブキーで離れると、そのパネルが閉じます。また、開いているパネルから兄弟のPopoverのボタン(PopoverGroup内)にタブキーで移動すると、最初のパネルが閉じます。 |
Shift + Tab | フォーカス順序を逆順に移動します |
ネストされたPopoverがサポートされており、ルートパネルが閉じると、すべてのパネルが正しく閉じます。
関連するすべてのARIA属性が自動的に管理されます。
Popoverと他の同様のコンポーネントの比較について説明します。
-
<Menu />
。Popover は Menu よりも汎用的です。Menu は非常に限定的なコンテンツしかサポートせず、特定のアクセシビリティセマンティクスを持っています。矢印キーでも Menu のアイテムを移動できます。Menu は、ほとんどのオペレーティングシステムのタイトルバーにあるようなメニューに似たUI要素に最適です。浮動パネルに画像や単純なリンク以上のマークアップが含まれる場合は、Popover を使用してください。 -
<Disclosure />
。Disclosure は、アコーディオンのように通常はドキュメントのレイアウトを変更する要素に役立ちます。Popover は Disclosure に加えて、オーバーレイを表示し、ユーザーがオーバーレイをクリック(Popover のコンテンツの外側をクリック)するか、Escキーを押すと閉じられるという追加の動作があります。UI 要素にこの動作が必要な場合は、Disclosure の代わりに Popover を使用してください。 -
<Dialog />
。Dialog は、ユーザーの完全な注意を引くことを目的としています。通常、画面中央に浮動パネルを表示し、バックドロップを使用してアプリケーションの残りのコンテンツを暗くします。また、フォーカスを取得し、Dialog が閉じられるまで Dialog のコンテンツからタブ移動できなくなります。Popover はよりコンテキストに依存し、通常はトリガーした要素の近くに配置されます。
メインの Popover コンポーネントです。
プロパティ | デフォルト値 | 説明 |
as | div | 文字列 | コンポーネント
|
スロットプロパティ | 説明 |
open |
Popover が開いているかどうか。 |
close |
Popover を閉じ、 |
プロパティ | デフォルト値 | 説明 |
as | div | 文字列 | コンポーネント
|
スロットプロパティ | 説明 |
open |
Popover が開いているかどうか。 |
これは、Popover を切り替えるためのトリガーコンポーネントです。PopoverPanel
内でこのPopoverButton
コンポーネントを使用することもできます。その場合、閉じボタンとして動作します。また、ボタンに適切なaria-*
属性が設定されるようにします。
プロパティ | デフォルト値 | 説明 |
as | button | 文字列 | コンポーネント
|
スロットプロパティ | 説明 |
open |
Popover が開いているかどうか。 |
プロパティ | デフォルト値 | 説明 |
as | div | 文字列 | コンポーネント
|
focus | false | ブール値
|
static | false | ブール値 要素が内部的に管理されている開閉状態を無視するかどうか。 注: |
unmount | true | ブール値 開閉状態に基づいて、要素をアンマウントするか、非表示にするかどうか。 注: |
スロットプロパティ | 説明 |
open |
Popover が開いているかどうか。 |
close |
Popover を閉じ、 |
PopoverGroup
で囲むことで、関連する兄弟 Popover をリンクします。ある PopoverPanel
からタブ移動すると、次の Popover の PopoverButton
にフォーカスが移動し、PopoverGroup
の外側にタブ移動すると、グループ内のすべての Popover が閉じます。
プロパティ | デフォルト値 | 説明 |
as | div | 文字列 | コンポーネント
|