HOME / BLOG
BLOG

HTMLのdialog要素でモーダルを作る方法【showModal・backdrop・閉じる処理】

デフォルト画像

モーダルを自作すると、画面中央への配置だけでなく、背景操作の抑制、フォーカス移動、Escキー、閉じた後のフォーカス復帰まで考える必要があります。HTMLの<dialog>要素を使うと、モーダルに必要な土台をブラウザ標準の仕組みで作れます。

この記事では、showModal()form method="dialog"::backdropを使い、確認モーダルをHTML・CSS・JavaScriptで実装します。

dialog要素を使うメリット

  • JavaScriptからshowModal()でモーダルとして開ける
  • モーダル表示中は背景側を操作しにくい状態にできる
  • Escキーによるキャンセル操作を標準の流れに乗せられる
  • ::backdropで背景オーバーレイを装飾できる
  • form method="dialog"でボタンの値を返しながら閉じられる

完成コード

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 MODAL</p>
  <h1>dialog要素で確認モーダル</h1>
  <button class="open-button" type="button">削除内容を確認</button>

  <dialog id="confirmDialog" aria-labelledby="dialogTitle">
    <form method="dialog">
      <p class="eyebrow">CONFIRM</p>
      <h2 id="dialogTitle">この項目を削除しますか?</h2>
      <p>削除後は元に戻せません。内容を確認して操作してください。</p>
      <div class="dialog-actions">
        <button value="cancel">キャンセル</button>
        <button class="danger" value="delete">削除する</button>
      </div>
    </form>
  </dialog>

  <p id="result" aria-live="polite">まだ操作されていません。</p>
</main>

CSS

* {
  box-sizing: border-box;
}

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

.demo-card {
  position: relative;
  width: min(100%, 560px);
  padding: 40px;
  border: 1px solid #d9dee8;
  background: #fff;
  box-shadow: 0 20px 50px rgb(18 33 63 / 10%);
}

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

button {
  min-height: 44px;
  padding: 10px 16px;
  border: 1px solid #111;
  background: #fff;
  color: #111;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
}

.open-button,
.danger {
  border-color: #0057ff;
  background: #0057ff;
  color: #fff;
}

dialog {
  width: min(calc(100% - 32px), 480px);
  padding: 0;
  border: 0;
  background: transparent;
}

dialog form {
  padding: 30px;
  border-left: 5px solid #0057ff;
  background: #fff;
  box-shadow: 0 24px 80px rgb(0 0 0 / 28%);
}

dialog::backdrop {
  background: rgb(5 12 24 / 72%);
  backdrop-filter: blur(3px);
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 24px;
}

@media (prefers-reduced-motion: no-preference) {
  dialog[open] {
    animation: dialog-in 180ms ease-out;
  }

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

JavaScript

const dialog = document.querySelector('#confirmDialog');
const openButton = document.querySelector('.open-button');
const result = document.querySelector('#result');

openButton.addEventListener('click', () => {
  dialog.showModal();
});

dialog.addEventListener('close', () => {
  result.textContent = dialog.returnValue === 'delete'
    ? '削除を選択しました。'
    : '操作をキャンセルしました。';
});

show()ではなくshowModal()を使う

dialog.show()は通常の非モーダル表示、dialog.showModal()はモーダル表示です。ユーザーに回答を求める確認画面ではshowModal()、画面の端に補助情報を残すような用途では非モーダル表示を検討します。

form method="dialog"の仕組み

ダイアログ内のフォームへmethod="dialog"を付けると、送信時にページ遷移せずダイアログを閉じられます。押されたボタンのvaluedialog.returnValueから取得できるため、キャンセルと実行を分けられます。

閉じる方法を整理する

操作使うもの用途
ボタンで閉じるform method="dialog"確認・キャンセルの選択
JavaScriptで閉じるdialog.close(value)処理完了後など任意のタイミング
Escキーcancelイベントキーボードによるキャンセル
閉じた後を処理closeイベントreturnValueの確認や画面更新

背景クリックで閉じる場合の注意

背景クリックで閉じる挙動は必須ではありません。重要な同意や破壊的操作では、誤操作を避けるため明示的なボタンだけにする方が安全です。追加する場合も、ダイアログ内部のクリックと背景のクリックを正しく区別します。

アクセシビリティで確認すること

  • 見出しを用意し、aria-labelledbyで関連付ける
  • ボタン文言を「はい/いいえ」だけでなく操作内容が分かる表現にする
  • 色だけで危険操作を示さず、テキストでも説明する
  • Escキーで閉じて問題ない設計かを確認する
  • 閉じた後に開いたボタンへフォーカスが戻るか実機で確認する
使い分け
ユーザーの判断を止めて回答を求めるならdialog、補足メニューや一時的な情報表示ならPopover APIが向いています。

CodePen埋め込み用エリア

dialog要素で作る確認モーダル
ここにCodePenのEmbedコードを貼り付けます。Pen作成後、このブロックと埋め込みタグを差し替えてください。

HTML、CSS、JavaScriptをそれぞれのパネルへ貼り付ければ動作します。まずはvalue="delete"を別の操作名へ変え、returnValueがどう変わるか試してください。

あわせて読みたい

参考資料

まとめ

<dialog>を使うと、確認モーダルの土台を少ないコードで作れます。showModal()で開き、method="dialog"で結果を返し、::backdropで背景を整えるのが基本です。独自のdivだけで作る前に、標準要素で要件を満たせるか確認しましょう。