モーダルダイアログ(背景を暗くして手前に表示する確認ウィンドウ)を作りたいとき、以前は div とオーバーレイ用の要素を組み合わせ、表示・非表示やフォーカス管理を自前で書く必要がありました。HTML の <dialog> 要素を使えば、こうした処理の多くをブラウザに任せられます。この記事では、showModal() と show() の違い、close() と returnValue、背景を装飾する ::backdrop、form の method="dialog" による閉じ方まで、MDN の仕様に沿って初心者〜中級者向けに解説します。実際に動くデモも用意したので、手を動かしながら確認してみてください。
目次
dialog 要素とは何か
<dialog> 要素は、ダイアログボックスやその他の対話的なコンポーネント(確認ウィンドウ、サブウィンドウなど)を表すための HTML 要素です。要素自体は最初は非表示になっており、JavaScript からメソッドを呼ぶか、open 属性を付けることで表示されます。対応するインターフェイスは HTMLDialogElement で、ここに showModal() や close() といったダイアログ専用のメソッドが用意されています。
大きな特徴は、モーダル表示にしたときにブラウザがオーバーレイ(背景)、フォーカスの閉じ込め、Esc キーでの閉じる操作といった面倒な部分を引き受けてくれる点です。まずは最小のコードで、ボタンを押すとダイアログが開き、別のボタンで閉じる例を見てみましょう。
showModal() で開いて close() で閉じる
基本の流れは、<dialog> 要素を HTML に置き、JavaScript から dialog.showModal() を呼んで開く、というものです。showModal() はダイアログをモーダルとして表示し、背景を暗くして、ダイアログの外側を操作できない状態にします。閉じるときは dialog.close() を呼びます。下のデモで、開くボタンと閉じるボタンの動きを確かめてみてください。
<div class="demo">
<button id="open">ダイアログを開く</button>
<dialog id="dialog">
<p>これはモーダルダイアログです。背景は暗くなり、ダイアログの外側は操作できません。</p>
<button id="close">閉じる</button>
</dialog>
</div>
.demo {
font-family: sans-serif;
padding: 8px;
}
button {
padding: 10px 18px;
border: none;
border-radius: 8px;
background: #007bff;
color: #fff;
font-size: 15px;
cursor: pointer;
}
button:hover {
background: #0069d9;
}
dialog {
border: none;
border-radius: 12px;
padding: 24px;
max-width: 320px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
/* showModal() で開いたときの背景(オーバーレイ) */
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
dialog p {
margin: 0 0 16px;
line-height: 1.7;
}
const dialog = document.getElementById("dialog");
const openBtn = document.getElementById("open");
const closeBtn = document.getElementById("close");
// showModal() でモーダルとして開く(背景が暗くなる)
openBtn.addEventListener("click", () => {
dialog.showModal();
});
// close() で閉じる
closeBtn.addEventListener("click", () => {
dialog.close();
});
このように、<dialog> の中身は普通の HTML として書けます。見出しや段落、ボタン、フォームなど、好きな要素を入れて構いません。開く・閉じるの操作だけを JavaScript で行えばよく、表示位置の中央寄せや背景の暗転はブラウザが面倒を見てくれます。
主なメソッド・属性とその効果
<dialog> 要素を扱ううえで覚えておきたいメソッド・プロパティ・属性を、効果と合わせて整理します。それぞれの役割を押さえておくと、開閉の制御や結果の受け取りで迷わなくなります。
| メソッド・属性 | 効果 |
|---|---|
showModal() | ダイアログをモーダルとして開く。背景に ::backdrop のオーバーレイが表示され、ダイアログの外側は操作できなくなる。 |
show() | ダイアログを非モーダルとして開く。背景は暗くならず、外側の操作も妨げない。 |
close() | ダイアログを閉じる。引数に文字列を渡すと、その値が returnValue に設定される。 |
returnValue | ダイアログを閉じたときの戻り値を保持する文字列のプロパティ。どのボタンで閉じたかなどを受け取れる。 |
open 属性 | ダイアログが開いているかどうかを示す論理属性。HTML に直接書くと非モーダルで開いた状態になる。 |
method="dialog" | ダイアログ内の form に指定すると、送信時に送信せずダイアログを閉じ、押したボタンの value を returnValue にする。 |
::backdrop | showModal() で開いたときに表示される背景部分を表す擬似要素。色や透明度をスタイルできる。 |
showModal と show では背景の暗転とキー操作が違う
ダイアログを開くメソッドには showModal() と show() の2つがあり、開いた後の挙動が大きく異なります。showModal() はモーダル表示で、ダイアログがトップレイヤーに表示され、背後の内容を ::backdrop のオーバーレイで覆います。このとき背後の要素はフォーカスもクリックもできなくなり、操作はダイアログの中に限定されます。
一方 show() は非モーダル表示です。ダイアログは表示されますが、背景は暗くならず(::backdrop も表示されません)、ダイアログの外側の要素もそのまま操作できます。さらに、後述する Esc キーでの自動的な閉じる動作も show() では働きません。「背景を暗くしたいのにならない」「外側がクリックできてしまう」というときは、show() を呼んでいないか確認してみてください。確認ダイアログのように操作を一度受け止めたい場面では showModal() を使います。
open 属性を直接書くとモーダルにはならない
<dialog open> のように HTML へ open 属性を直接書くと、ページの読み込み時点でダイアログが開いた状態になります。ただしこの方法で開いた場合、表示は非モーダルになります。showModal() で開いたときのように背景が暗くなることはなく、トップレイヤーにも配置されません。
MDN でも、open 属性を使ってモーダルダイアログを開く方法は推奨されていません。モーダルとして表示したいなら、HTML には open を書かず、JavaScript で showModal() を呼ぶのが正しい手順です。「背景が暗くならない」という相談の多くは、属性で開いてしまっているか、show() を使っているかのどちらかです。
Esc キーで閉じるのは showModal のときだけ
showModal() で開いたモーダルダイアログは、ユーザーが Esc キーを押すと自動的に閉じます。これはブラウザが標準で提供する挙動で、こちらで keydown を監視するコードを書く必要はありません。閉じられたときには、後述する close イベントが発火します。
注意したいのは、この Esc による閉じる動作が モーダル表示のときだけに働く点です。show() で非モーダルとして開いたダイアログや、open 属性で開いた状態では、Esc を押しても閉じません。閉じる手段が必要なら、自分で閉じるボタンを用意して close() を呼ぶようにします。
form の method=”dialog” で閉じて結果を受け取る
ダイアログの中に <form method="dialog"> を置くと、そのフォームの送信ボタンを押したときにサーバーへ送信されることなく、ダイアログが閉じます。このとき、押した送信ボタンの value 属性の値が、ダイアログの returnValue プロパティに設定されます。つまり「OK」と「キャンセル」のどちらが押されたかを、returnValue を見るだけで判別できます。
閉じられたタイミングは close イベントで検知できます。下のデモでは、確認ダイアログを showModal() で開き、「注文する」または「キャンセル」を押して閉じたあと、returnValue の値に応じてメッセージを切り替えています。閉じるためのボタンに close() を呼ぶ JavaScript を書かなくても、method="dialog" だけで閉じられる点に注目してください。
<div class="demo">
<button id="open">注文を確認する</button>
<p class="result" id="result">ボタンを押すと、method="dialog" のフォームで閉じます。</p>
<dialog id="dialog">
<form method="dialog">
<p>この内容で注文しますか?</p>
<div class="actions">
<button value="cancel">キャンセル</button>
<button value="ok">注文する</button>
</div>
</form>
</dialog>
</div>
.demo {
font-family: sans-serif;
padding: 8px;
}
button {
padding: 10px 18px;
border: none;
border-radius: 8px;
background: #007bff;
color: #fff;
font-size: 15px;
cursor: pointer;
}
button:hover {
background: #0069d9;
}
.result {
margin: 16px 0 0;
padding: 12px;
background: #f1f3f5;
border-radius: 8px;
}
dialog {
border: none;
border-radius: 12px;
padding: 24px;
max-width: 320px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
dialog p {
margin: 0 0 16px;
}
.actions {
display: flex;
gap: 8px;
justify-content: flex-end;
}
const dialog = document.getElementById("dialog");
const openBtn = document.getElementById("open");
const result = document.getElementById("result");
openBtn.addEventListener("click", () => {
dialog.showModal();
});
// method="dialog" のフォーム送信で閉じると、
// 押したボタンの value が returnValue に入る
dialog.addEventListener("close", () => {
if (dialog.returnValue === "ok") {
result.textContent = "注文を確定しました(returnValue: ok)";
} else {
result.textContent = "キャンセルしました(returnValue: cancel)";
}
});
同じことは JavaScript の close() でも行えます。dialog.close("ok") のように引数に文字列を渡すと、その値が returnValue に入ります。フォームを使うかメソッドを使うかは状況次第ですが、確認ダイアログのように選択肢が固定されているなら、method="dialog" を使うとボタンごとに JavaScript を書かずに済みます。
::backdrop で背景のオーバーレイを装飾する
showModal() で開いたモーダルダイアログの背後には、::backdrop という擬似要素で表される背景レイヤーが敷かれます。この擬似要素は dialog::backdrop というセレクタでスタイルでき、背景色や透明度、ぼかしなどを指定できます。先のデモでも background: rgba(0, 0, 0, 0.5) を指定して、背後を半透明の黒で覆っていました。
/* showModal() のときだけ表示される背景レイヤー */
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px); /* 背後をぼかす */
}
::backdrop はモーダル表示のときにだけ生成されます。show() で開いた非モーダルのダイアログや、open 属性で開いた状態では背景レイヤーが作られないため、dialog::backdrop を書いてもスタイルは反映されません。「背景に色を付けたのに変わらない」というときは、showModal() で開いているかをまず確認しましょう。
まとめ
<dialog> 要素を使うと、背景の暗転やフォーカス管理を自前で書かずにモーダルダイアログを作れます。モーダルとして開くなら showModal()、背景を暗くしたくない非モーダルなら show() を使い分けます。閉じるのは close() で、引数や form の method="dialog" を使えば、どのボタンで閉じたかを returnValue から受け取れます。Esc キーでの自動的な閉じる動作と、::backdrop による背景の装飾は、いずれも showModal() で開いたモーダルのときだけ働きます。逆に open 属性を直接書いて開くと非モーダルになり、背景は暗くなりません。この対応関係を押さえておけば、思った通りのダイアログを安定して作れます。