【HTML】popover と dialog との関係性について調べてみた


## 背景
フロントエンド開発にて度々登場するUIパーツPopover、dialogについて、見た目など結構似ているので、どういった概念の違いがあって、どんな使い分けをするのかが気になったので自分なりに整理してみました。

## 簡単な使いかた
HTMLの属性としてpopup、タグとしてdialogは存在しています。
それらの簡単な使い方をみていきましょう。


## popover
https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/popover

>popover はグローバル属性で、要素をポップオーバー要素として示すために使われます。

とあるので`popover`属性を要素に付与して使用するため、`<div popover>`のように任意の要素を`popover`アイテムとして扱うことができる


### デモ
以下のように非モーダルをJSの記述抜きで作成することができます。
<p class="codepen" data-height="300" data-default-tab="html" data-slug-hash="WbeKOBO" data-pen-title="popup" data-user="kobax" 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/kobax/pen/WbeKOBO">
  popup</a> by KobayashiMakoto (<a href="https://codepen.io/kobax">@kobax</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>


## dialog
過去に記事としてまとめたことがあります。
[【HTML】便利そうな dialog 使ってみた感想
](https://qiita.com/kobayashimakoto/items/c5248c23c7d13cc640c5
)


dialog は htmlの要素の一つで、以下のように使うことができます。
JSによってモーダルの開閉を制御することになります。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="vYQJWBa" data-user="knicisow-the-vuer" 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/knicisow-the-vuer/pen/vYQJWBa">
  Untitled</a> by 小林誠 (<a href="https://codepen.io/knicisow-the-vuer">@knicisow-the-vuer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

dialog には標準Roleとして、[dialog](https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Roles/dialog_role)が存在しています。

そのため、`<div role="dialog"` のように書くと、支援技術がダイアログとして識別するのに役立ちます。（実際はこれだけでは足りないが、手動でroleを設定できるということ）



## 両者の区別はどうすればいいのか
使い方の表面を見た限りでは、属性（popover）とHTML要素（dialog）と随分違うはずなのに、機能的にはそこまで違いがないように思いました。
（※ 素人目線での感想です）
これらは一体どうやって区別するのがいいのでしょうか...？


機能的な面で考えた時に以下の記事に興味深いことが書かれていました。
[Comparing the Popover API and the <dialog> element](https://blog.logrocket.com/comparing-popover-api-dialog-element/)

また、`aria-hasPopUp` という属性の観点から分類を考えることができるという記事も面白いです。
[Clarifying the Relationship Between Popovers and Dialogs](https://css-tricks.com/clarifying-the-relationship-between-popovers-and-dialogs/)

自分なりに理解したことをまとめてみます。

## 機能的な面で使い分けを考える

### モーダルダイアログ
モーダルダイアログが開いていると、ユーザーは**ダイアログを処理しないとアプリに戻れません**。つまり、ダイアログを閉じるかキャンセルするまで、アプリ内で他の操作ができないことを意味します。

ちなみに、ダイアログ（＝dialo, dialogue）とは、対話、話し合いという意味を持ちます。つまり、UIにおけるダイアログとは、**アプリとユーザー間の「対話」であり、ユーザーへの情報や行動の要求**を指します。

### 非モーダル
非モーダルダイアログとはダイアログが開いているときでもユーザーがアプリを使用できます。つまり、ダイアログの背景要素がないという状態です。
明確に区別するため、
`ダイアログ vs ポップオーバー` → `モーダル vs 非モーダル`
 と考えて議論することもあるそうです。

 dialog要素は`Dialog.show()`と`Dialog.showModal()`を使い分けることで、モーダル/非モーダルの使い分けをすることができます。

 ### popover 
ポップオーバーとは、アプリ内でトリガーされたときに一時的に現れるウィンドウのようなUIです。ユーザーに追加情報や機能を提供するために使用されることが多いです。
 
`Popover` は非モーダルな振る舞いをし、`dialog`と比べて、静かにトリガーしたり解除したりする `UI ` を簡単に提供できます。
- ツールチップやヘルプテキスト
- トースト通知、ホバーカードなどの非モーダルダイアログ
といった機能を作成する時に使用します。

### 中間 まとめ
`dialog` はモーダル/非モーダル を `CSS,JS` で作成できる。
`popover` は`JS`を記述せずとも、非モーダルな挙動を簡単に実現できる。
以上のことから、ツールチップなどのアクション関連情報を提示するような非モーダルなら`popover`を使用する方がよく、ユーザーの操作（`focus`）を要求するようなモーダルを実装するなら、`dialog` を使うという感じでしょうか。


## 属性の分類から考えてみる



結論から述べると、以下のような分類関係にあると述べています。

<img width='400' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/b166b99a-8dfa-51f3-bd88-1f3490bc31aa.png'>

根拠として [aria-hasPopUp](https://developer.mozilla.org/ja/docs/Web/API/Element/ariaHasPopup) に焦点を当てています。
これは、ボタンをクリック/ホバー/焦点を合わせると「ポップアップするコンテンツである」ことを理解できるように5つのroleに分類されています。

以下のように使用することで、スクリーンリーダーでは、ボタンの読み上げに加え「ポップアップがあります」「サブメニュー」といった内容が読み上げられるようになります。
```html
<button type="button" aria-haspopup="true">メニュー</button>
```

`dialog`がこの分類の一種であることから、
**`dialog`がポップオーバーの一種である**ことをなんとなく察することができます。


### dialogの分類から考える
ダイアログは **モーダル/非モーダル/アラートダイアログ** の3つに分類できます。

<img width='400' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/a6b86dcf-73fb-cc5f-cb2f-2845c309eb4c.png'>

「ポップオーバー == 非モーダル」という意見もありますが、
実際は異なるかもしれません。

なぜなら、「**::backdropの存在は、その要素がモーダルである**ことを示唆しており、
**ポップオーバーにはトップレイヤーに::backdrop疑似要素がある**から」という主張があるからです
参考: https://css-tricks.com/almanac/pseudo-selectors/b/backdrop/


（以下のように`::backdrop` 疑似要素は確認できる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/02b1b55d-343e-a6f9-f839-85f084d3bbe0.png)

### ポップオーバーの特徴
また、**ポップオーバーにはインタラクティブな要素（ボタンなどのアクセス可能な要素）が含まれている必要があります。**

[ariaHasPopup](https://developer.mozilla.org/ja/docs/Web/API/Element/ariaHasPopup)にある通り、ユーザーとの対話が発生するからです。
>要素によって発生させることができるメニューやダイアログなどの対話型ポップアップ要素の型と利用できるかどうかを示します。


### ツールチップに対する言及
見た目上、ツールチップはポップオーバーになるはずです。
しかし、**ツールチップは`aria-hasPopUp` には含まれていません。**

ツールチップにはインタラクティブな要素（ボタンなど操作可能な要素）が含まれることはありません。操作可能なら ダイアログを使用するべきだからです。

[Semantics and the popover attribute: which role to use when?](https://hidde.blog/popover-semantics/)
ユーザーとの対話を望むなら、`dialog` を使用した方がいいという主張の記事もあります

### 中間まとめ
**ポップオーバーは**、ユーザーの操作や特定の条件に応じて表示される様々な種類のポップアップUIを指し、これには、ツールチップ、コンテキストメニュー、モーダルダイアログ、通知など、画面上に一時的に表示される様々な要素が含まれる。

**ダイアログは**、ポップオーバーの一種であり、新しいカードを作成してユーザーと対話するためのインタラクティブなコンテンツを含む。


## まとめ
モーダルダイアログが「ユーザーとアプリケーションの対話」するためにあるという解釈が個人的に新鮮でした。

UIコンポーネントがどのような目的で存在するのかを知っていると、自分がデザインを設計する時に、どんな時にどんなUIコンポーネントを使うべきかの取捨選択のヒントになってくれるのではないかと希望を持ちました。