Popover API — JavaScriptなしでツールチップが作れるようになった理由
popover属性1つで開閉・Escキー・アクセシビリティが自動動作するブラウザネイティブUI
<button popovertarget="tip-1">ホバー</button>
<div id="tip-1" popover="auto" role="tooltip">
ネイティブツールチップ
</div>
JavaScript 0行。イベントリスナーなし。状態追跡なし。それでもEscで閉じ、キーボードでアクセスでき、スクリーンリーダーが正しく読み上げる。
従来のツールチップが壊れる理由
「ホバーで表示、離れたら非表示」という単純な要件。実際にデプロイすると問題が噴出する。
キーボードユーザーがTabでトリガーに到達してもツールチップが出ない。スクリーンリーダーが2回読むか、全く読まない。マウスを速く動かすとちらつく。小さい画面で重なる。Escで閉じない。フォーカスが失われる。
イベントリスナーが積み重なる。hover/focus別々の処理。外部クリックの特殊ケース。ARIA属性の手動同期。コードが肥大化する。実装の問題ではなく、Webプラットフォームに「この要素はツールチップだ」という概念がなかったからだ。
Popover APIが変えたこと
popover属性を付けるとブラウザがこの要素の役割を理解する。3つが自動で解決。
1. JavaScriptなしで開閉
popovertarget="id"でボタンとpopoverを接続するだけ。クリック、フォーカスでの開閉をブラウザが処理。popovertargetactionでshow、hide、toggle(デフォルト)を指定可能。
2. Escキー自動処理
グローバルkeydownハンドラ不要。Esc専用のクリーンアップロジック不要。ブラウザがpopoverを解除可能な要素と認識する。
3. ARIA状態の自動同期
aria-expandedがpopoverの開閉に合わせて自動更新。手動管理不要。古い状態が残るリスクがない。
auto vs manual
autoは外部クリック、Esc、別のauto popover表示で自動的に閉じる。ツールチップ向け。
manualは明示的に閉じる必要がある。フォーカス復元も自動ではない。トースト通知向け。
まだJavaScriptが必要な領域
タイミング制御。ネイティブpopoverは即座に開閉する。マウスを速く動かすとちらつく問題は残る。ディレイが必要ならJavaScript。
ホバーインテント。ブラウザはポインターがなぜ要素上にあるか分からない — 意図的か通過中か判断できない。
ただし核心が変わった。JavaScriptはもう相互作用モデル全体を所有しない。Popover APIが基本開閉を処理し、JavaScriptはその上にインテント判別だけを載せる。
ライブラリが依然有効な場合
複雑なポジショニング — ネストしたスクロールコンテナ間の衝突検出、カスタムフリッピングロジックが必要ならFloating UIが依然優位。CSS anchor positioningが登場しつつあるが初期段階。
大規模デザインシステム — チーム横断で一貫した動作とガードレールが必要な場合。
ほとんどの場合 — 単純なツールチップ、ドロップダウンメニュー、トースト通知 — Popover APIだけで十分だ。ライブラリなしで。
キーポイント
popover属性とpopovertargetだけで開閉・Esc・キーボードナビゲーションが自動動作
aria-expanded自動同期でアクセシビリティバグのカテゴリ自体が消える
autoは外部クリック/Escで自動閉鎖、manualは明示的制御 — 用途で選択
タイミング制御やホバーインテントは依然JavaScriptが必要だが、核心モデルはブラウザ担当