HOME / BLOG
BLOG

HTMLのPopover APIでメニューを作る方法【popovertarget・開閉制御】

デフォルト画像

ドロップダウンメニューや補足パネルを作るとき、表示・非表示だけならCSSでも実装できます。しかし、外側をクリックしたら閉じる、Escキーで閉じる、ほかの一時表示と重ならないようにする、といった挙動まで自作するとコードが増えます。

Popover APIを使うと、HTMLのpopover属性とpopovertarget属性を中心に、一時的なUIをブラウザ標準の仕組みで開閉できます。この記事ではプロフィールメニューを作ります。

Popover APIでできること

  • popovertargetを付けたボタンから対象を開閉できる
  • 一時表示の外側を操作したときに閉じる挙動を利用できる
  • Escキーで閉じる操作を標準の流れに乗せられる
  • JavaScriptからshowPopover()hidePopover()togglePopover()を呼べる
  • :popover-openで開いている状態だけを装飾できる

完成コード

HTML

<main class="demo-card">
  <img class="nines-logo" src="https://kjnine.com/wp-content/themes/kjnines_theme/images/svg2/nines_logo.svg" alt="NINES">
  <p class="eyebrow">NATIVE POPOVER</p>
  <h1>プロフィールメニュー</h1>

  <button class="menu-button" type="button" popovertarget="profileMenu">
    メニューを開く
  </button>

  <nav id="profileMenu" class="profile-menu" popover aria-label="プロフィールメニュー">
    <a href="#profile">プロフィール</a>
    <a href="#settings">設定</a>
    <button type="button" data-logout>ログアウト</button>
  </nav>
</main>

CSS

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #eef2f7;
  color: #111;
  font-family: system-ui, sans-serif;
}

.demo-card {
  position: relative;
  width: min(100%, 520px);
  padding: 40px;
  border: 1px solid #dce2ec;
  background: #fff;
}

.nines-logo {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 58px;
  opacity: 0.16;
}

.eyebrow {
  color: #0057ff;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
}

.menu-button {
  min-height: 44px;
  padding: 10px 16px;
  border: 0;
  background: #0057ff;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-weight: 800;
}

.profile-menu {
  width: min(260px, calc(100vw - 32px));
  margin: auto;
  padding: 8px;
  border: 1px solid #cfd6e3;
  background: #fff;
  box-shadow: 0 18px 50px rgb(15 30 60 / 22%);
}

.profile-menu a,
.profile-menu button {
  display: block;
  width: 100%;
  padding: 12px;
  border: 0;
  background: transparent;
  color: #111;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  font: inherit;
}

.profile-menu a:hover,
.profile-menu button:hover,
.profile-menu a:focus-visible,
.profile-menu button:focus-visible {
  background: #edf3ff;
  outline: 2px solid #0057ff;
  outline-offset: -2px;
}

@media (prefers-reduced-motion: no-preference) {
  .profile-menu:popover-open {
    animation: popover-in 160ms ease-out;
  }

  @keyframes popover-in {
    from {
      opacity: 0;
      transform: translateY(-8px) scale(0.98);
    }
  }
}

JavaScript

const menu = document.querySelector('#profileMenu');
const logoutButton = document.querySelector('[data-logout]');

menu.addEventListener('toggle', (event) => {
  console.log(`Popover is now ${event.newState}`);
});

logoutButton.addEventListener('click', () => {
  menu.hidePopover();
  alert('ログアウト処理へ進みます。');
});

HTMLだけで開閉する仕組み

ボタンのpopovertarget="profileMenu"と、表示する要素のid="profileMenu" popoverを一致させます。これだけで開閉できます。単純なメニューなら、開閉のためだけのJavaScriptは必要ありません。

popoverのautoとmanual

指定特徴向いている用途
popover または popover="auto"外側操作やEscで閉じる一時表示メニュー、補足、選択肢
popover="manual"JavaScriptなどで明示的に閉じる複数同時表示、通知、独自制御

通常のドロップダウンメニューはautoから始めると自然です。通知を複数残したい場合など、軽い解除で閉じてほしくないUIではmanualを検討します。

JavaScriptが必要になる場面

  • データ取得後に開きたい
  • 特定の処理完了後に閉じたい
  • 開閉状態をログや分析へ送信したい
  • フォーム入力の状態に応じて開閉を止めたい

開閉状態はtoggleイベントで確認できます。サンプルではログアウトボタンを押したときにhidePopover()を呼び、処理へ進む前にメニューを閉じています。

dialogとの使い分け

UIユーザー操作
Popover一時的な補助。外側操作で閉じてもよいメニュー、ツールチップ、補足
dialog回答や確認を求める。操作を中断させる削除確認、同意、入力フォーム

アクセシビリティの注意点

  • 開閉ボタンの文言だけで目的が分かるようにする
  • ナビゲーションならnavと適切なラベルを使う
  • リンクと実行ボタンを役割に合わせて使い分ける
  • ホバーだけを開閉条件にせず、キーボードとタップでも操作できるようにする
  • 開いた後のフォーカス順を実機で確認する

ボタンの近くへ配置する

Popover APIは開閉を担当します。表示位置をトリガーボタンへ追従させたい場合は、CSS Anchor Positioningを組み合わせると、絶対位置の座標計算を減らせます。未対応環境も考慮し、中央表示など読めるフォールバックを残します。

CodePen埋め込み用エリア

Popover APIで作るプロフィールメニュー
ここにCodePenのEmbedコードを貼り付けます。Pen作成後、このブロックと埋め込みタグを差し替えてください。

HTML、CSS、JavaScriptを各パネルへ貼り付けて試せます。最初はJavaScriptなしでも開閉できることを確認し、その後でtoggleイベントを追加してください。

あわせて読みたい

参考資料

まとめ

Popover APIを使うと、ドロップダウンメニューの開閉をHTML中心に実装できます。まずpopoverpopovertargetで基本を作り、必要な場面だけJavaScriptを足すのが分かりやすい構成です。モーダルはdialog、位置合わせはCSS Anchor Positioningと役割を分けましょう。