Popover APIが便利そう

# 導入
Chrome 114からサポートされたPopover APIを使用することでJavascriptなしで簡単にポップオーバーを実装できるようになりました。

# ポップオーバーとモーダル
ポップオーバーと似たUIにはモーダルがありますが、そもそもポップオーバーとモーダルは何が違うのでしょうか？
MDNによると、
> * モーダルというのは、ポップオーバーが示されている間、ページの残りの部分は、ポップオーバーが何らかのアクションを起こすまで（例えば、重要な選択がなされるまで）、反応しないようにレンダリングされるということです。
> * 非モーダルというのは、ポップオーバーが表示されている間も、ページの残りの部分が反応するようにするということです。

とのことです。[(https://developer.mozilla.org/ja/docs/Web/API/Popover_API)](https://developer.mozilla.org/ja/docs/Web/API/Popover_API)
今回紹介するPopover APIは表示されている間は他の要素を操作できるUIであるため後者の非モーダルにあたります。
モーダルが表示されている間は、モーダル以外の部分を操作されないようにしたいという場合はライブラリやHTMLのdialog要素などを使うのが良さそうです。

# Popover APIとは
Popover APIはコンテンツ上に別のコンテンツを表示しユーザーをサポートするようなコンポーネントをjavascriptを使うことなく実装できる便利な機能です。
Popover APIがサポートされたことにより、**popover**、**popovertarget**、**popovertargetaction**の3つの属性が新たに追加され、それらの属性をHTMLタグに記述することで使用が可能です。
<table>
  <tr>
    <td><b>popover<b></td> <td>ポップオーバーとなる要素に記述</td>
  </tr>
  <tr>
    <td><b>popovertarget<b></td> <td>ポップオーバーを展開するbuttonタグに記述</td>
  </tr>
  <tr>
    <td><b>popovertargetaction<b></td> <td>ポップオーバーを展開するbuttonタグに記述<br><b>toggle</b>、<b>show</b>、<b>hide</b>の三種類からなるアクションを指定できる</td>
  </tr>
</table>

## Popoverの機能
Popover APIには便利な機能が標準で搭載されているため紹介します。
### 最上位のレイヤーに配置される
ポップオーバーが最上位に出現するため、z-indexを調整する必要がありません。
### ライトディスミス機能
<b>簡易非表示</b>という概念であり、
* ESCキーで閉じる
* ポップオーバーの外側をクリックすると閉じる

という機能で、ポップオーバー外をクリックして閉じるという動作を標準で対応しており、ESCキーで閉じることができるためアクセシビリティにも配慮されています。

### 複数のポップオーバーがあった場合は勝手に他を閉じてくれる
一つ目のポップオーバーを開いた状態で二つ目のポップオーバーを開くと自動的に一つ目のポップオーバーを閉じてくれます。

## 実装方法
実装方法は至ってシンプルです。
1. ポップオーバーにしたい要素にpopover属性と任意のidを付与
1. ポップオーバーの開閉を制御したい要素にpopovertarget属性を付与し、popover属性に与えたidを指定
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxMmgRv" data-user="gama604" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/gama604/pen/xxMmgRv">
  popover</a> by gama604 (<a href="https://codepen.io/gama604">@gama604</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


これだけで簡単にポップオーバーを実装することができます。

## 自動ポップオーバーと手動ポップオーバー
popover属性のデフォルト値は`auto`ですが、値を変えることで動作を変更することができます。
`popover="manual"`と記述した場合、ライトディスミス機能である、ESCキーで閉じる、ポップオーバーの外側をクリックすると閉じるといった機能がオフになります。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="OJddWdx" data-user="gama604" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/gama604/pen/OJddWdx">
  popover manual</a> by gama604 (<a href="https://codepen.io/gama604">@gama604</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

上記のデモでは、ポップオーバーを展開した後、ポップオーバーの外側をクリック、ESCキーを押下してもポップオーバーを非表示にできないことが確認できると思います。
また、他のポップオーバーが表示されていてもmanualを設定しているポップオーバーは自動的に閉じることはありません。

## popover要素のスタイリング
Popover APIには疑似クラスと疑似要素が存在します。
* ` ::popover-open`
ポップオーバーが開いた状態を指す疑似クラス
* `::backdrop`
ポップオーバーが開いた際にポップオーバーの背景として配置される疑似要素

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="LYqXJqr" data-user="gama604" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/gama604/pen/LYqXJqr">
  Untitled</a> by gama604 (<a href="https://codepen.io/gama604">@gama604</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

フェードイン限定ではありますが、`@keyframes`を使用することでアニメーションを実装することも可能です。
フェードアウトはポップオーバーを閉じる際にpopover属性の仕様で`display:none;`が適応されてしまうためJavaScriptを使用する必要があります。

## JavaScriptを使用する実装方法
JavaScriptなしでポップオーバーを実装することはもちろん可能ですが、JavaScriptを使用することでより目的に合った実装をすることができます。
マウスオーバーやフォーカスを当てることでもポップオーバーを表示することも可能です。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="BaMvpJm" data-user="gama604" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/gama604/pen/BaMvpJm">
  Untitled</a> by gama604 (<a href="https://codepen.io/gama604">@gama604</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 実際に使用する場合
ここまでPopover apiを紹介しましたが、どのような場面で活用できるのでしょうか？
ポップオーバーは非モーダルに分類され、表示されている間もユーザーの操作を制限しないUIです。そのため、画面上に表示される通知やトースターで使用することができると思います。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="QWYYpWV" data-user="gama604" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/gama604/pen/QWYYpWV">
  popover samp</a> by gama604 (<a href="https://codepen.io/gama604">@gama604</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 対応ブラウザ
ポップオーバーAPIは記事投稿時点(2023年12月8日)ではChrome 114・Edge 114以上、Safari 17以上が対応しており、その他のブラウザでは対応しておりません。(参照 : [Can I use...](https://caniuse.com/mdn-api_htmlelement_popover))
Firefoxで使用する場合は、有志の方によって提供されているポリフィル（[Popover Attribute Polyfill](https://github.com/oddbird/popover-polyfill)）があるためそちらを導入する必要があります。

# 参考にさせていただいた記事
ここまで読んでいただきありがとうございました。
下記に参考にさせていただいた記事を記載しましたので興味を持った方はぜひ読んでみてください。

* https://ics.media/entry/230530/
* https://zenn.dev/yusukehirao/articles/popover-api-and-attributes
* https://zenn.dev/yusukehirao/articles/popover-api-and-attributes
* https://coliss.com/articles/build-websites/operation/css/about-popover-api.html