Popover APIを使ってJavaScriptなしで要素の側に異なる要素を表示する
Popover APIは、ツールチップやドロップダウンメニューをJavaScriptなしで実装できるAPIで、2025年のBaselineに追加されました。表示するコンテンツにpopover属性を渡し、その要素をpopovertargetで制御します。シンプルなHTMLとCSSで手軽に機能に富んだポップオーバーを作成する方法を学びます。
はじめに
Popover APIがついに2025年のBaselineに追加されました。 Popover APIはツールチップやドロップダウンメニューのようなUIを作成するためのAPIです。
ツールチップとドロップダウンメニュー
Tooltip
Dropdown Menu
このUIの実装はPopover APIを使っていません。
これらのUIは、重ね合わせコンテキストの階層の管理やアクセシビリティを考慮した実装がかなりハードルが高く、ライブラリを頼らざるを得ないことが多かったのでBaselineに追加されたことは大きな進歩です。
Popover APIでは表示位置までは決められません。CSS Anchor Positioningが利用可能になると表示位置も決められるので後一歩といった感じですね。
Popover APIの全体像
Popover APIによって作られたポップオーバーは
- その外側をクリックすると閉じられる
- ESCキーを押すと閉じられる
- 開いた時にフォーカスが内部に移動する
- Top layer(重ね合わせコンテキストの最上位のレイヤー)に配置される
の性質を持ちます。
Popover APIは関連する3つのHTMLの属性と2つのCSSの機能が用意されています(それらを管理するJavaScriptの機能も存在しますが、この記事ではHMTLとCSSにだけ注目します)。
HTMLの属性はpopover
とpopovertarget
、popovertargetaction
、CSSの機能は::backdrop
と:popover-open
です。
HTML属性
popover
属性はポップオーバーで表示させたいコンテンツを指定します。
<p id="popover1" popover>ポップオーバーで表示されるコンテンツ</p>
デフォルトの値はauto
です(JSXで記述する際は明示的に付与する必要がありそうです)。値をmanual
にするとESCキーの押下や外側のクリックで閉じられなくなります。manual
は主にJavaScriptを使って制御する場合に使用します。
ポップオーバーの表示を管理する要素にはpopovertarget
属性を付与します。管理するコンテンツを伝えるために、値にはpopover
を持たせた要素のid
を渡します。
<button popovertarget="popover1">
ポップオーバーの表示を管理する要素
</button>
popovertargetaction
はpopovertarget
属性が付与された要素がどのように管理するかを示します。
<button popovertarget="popover1" popovertargetaction="show">
クリックでポップオーバーを表示
</button>
デフォルトは表示非表示を切り替えるtoggle
です。その他にも表示だけさせるshow
と、非表示にするだけのhide
があります。
CSS機能
ポップオーバー要素の後ろには全画面を覆うコンテンツが配置されます。::backdrop
はそんな背景にスタイルを付与するための擬似要素です。
::backdrop {
background-color: #00000080;
}
::backdrop
はPopover API専用の擬似要素ではなく、dialog
要素のようなTop Layerに配置される要素の背景にスタイルを渡す時に利用されます。
:popover-open
はポップオーバーが表示されたときにスタイルを付与する擬似クラスです。
.popover:popover-open {
min-width: 50vw;
}
サンプル
Popover APIを使った簡単な例を紹介します。3つのボタンがあり、それぞれ異なるpopovertargetaction
を持っています。
表示されるコンテンツは:popover-open
を利用して、開閉時のアニメーションを付与しています。
Popover APIのサンプル
このポップオーバーはPopover APIによって表示されました。 ESCキーやこのコンテンツの外側のクリック、toggleまたはhideボタンで閉じられます。
<div class="wrapper">
<button popovertarget="popover1" popovertargetaction="toggle">
popovertargetaction: toggle
</button>
<button popovertarget="popover1" popovertargetaction="show">
popovertargetaction: show
</button>
<button popovertarget="popover1" popovertargetaction="hide">
popovertargetaction: hide
</button>
</div>
<p id="popover1" popover>
このポップオーバーはPopover APIによって表示されました。
ESCキーやこのコンテンツの外側のクリック、toggleまたはhideボタンで閉じられます。
</p>
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
#popover1 {
border-radius: 0.5rem;
margin: auto;
padding: 1rem;
max-width: calc(1 / 3 * 100%);
opacity: 0;
transition: opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
#popover1:popover-open {
opacity: 1;
}
@starting-style {
#popover1:popover-open {
opacity: 0;
}
}
::backdrop {
background-color: #00000080;
}