k8o

Popover APIを使ってJavaScriptなしで要素の側に異なる要素を表示する

公開: 2025年3月17日(月)
更新: 2025年3月28日(金)
閲覧数34 views

Popover APIは、ツールチップやドロップダウンメニューをJavaScriptなしで実装できるAPIで、2025年のBaselineに追加されました。表示するコンテンツにpopover属性を渡し、その要素をpopovertargetで制御します。シンプルなHTMLとCSSで手軽に機能に富んだポップオーバーを作成する方法を学びます。

JavaScriptBaseline 2025Popover API

はじめに

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の属性はpopoverpopovertargetpopovertargetaction、CSSの機能は::backdrop:popover-openです。

HTML属性

popover属性はポップオーバーで表示させたいコンテンツを指定します。

<p id="popover1" popover>ポップオーバーで表示されるコンテンツ</p>

デフォルトの値はautoです(JSXで記述する際は明示的に付与する必要がありそうです)。値をmanualにするとESCキーの押下や外側のクリックで閉じられなくなります。manualは主にJavaScriptを使って制御する場合に使用します。

ポップオーバーの表示を管理する要素にはpopovertarget属性を付与します。管理するコンテンツを伝えるために、値にはpopoverを持たせた要素のidを渡します。

<button popovertarget="popover1">
  ポップオーバーの表示を管理する要素
</button>

popovertargetactionpopovertarget属性が付与された要素がどのように管理するかを示します。

<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;
}