HTMLのdialog
要素を利用すると、モーダルダイアログをシンプルに実装できます。dialog
要素は、2022年頃から主要ブラウザで利用可能です。
モーダルとは、表示している間は他の操作を禁止し、ある操作が完了するまで先に進めなくするUIを指します。dialog
要素の登場以前は、次のような制御が必要で複雑でした。
- 画面の最前面にモーダルUIを表示する
- モーダルUIが表示されている間、ほかの操作を制限する
- モーダルUI開閉時に、フォーカス位置を調整する
こうした複雑さについては記事『HTMLでモーダルUIを作るときに気をつけたいこと』でも解説していますので、あわせて参考にしてください。
dialog
要素を利用すれば、HTMLが標準で提供する仕組みによって、シンプルかつ一貫した方法でモーダルダイアログを扱えるようになります。本記事では、dialog
要素の基本的な使い方を紹介します。
本記事で紹介すること:
dialog
要素の基本的な使い方closedby
やautofocus
などの便利な属性- CSSでスタイルを適用する例
dialog
要素の使い方
まずは次の作例とコードをご覧ください。この作例は、dialog
要素で実装したモーダルダイアログです。ボタンを押下することでモーダルダイアログの表示を切り替えます。
<button id="showDialog">モーダルダイアログを開く</button>
<dialog>
<p>ダイアログボックスの説明文が入ります。</p>
<button id="closeDialog">閉じる</button>
</dialog>
const dialog = document.querySelector("dialog");
const showButton = document.querySelector("#showDialog");
showButton.addEventListener("click", () => {
dialog.showModal(); // モーダルダイアログを開く
});
const closeButton = document.querySelector("#closeDialog");
closeButton.addEventListener("click", () => {
dialog.close(); // モーダルダイアログを閉じる
});
モーダルダイアログを開くボタンが押下されると、ボタンの上にdialog
要素が重なって表示されます。表示されている間は、モーダルダイアログを開くボタンは押下できません。
dialog
要素は、標準仕様で次の機能を提供します。
- ダイアログボックスを画面の最前面に表示する
- 子要素をボックス内のコンテンツとして表示する
showModal()
/close()
などの開閉用API- 表示されている間はほかの操作を制限し、閉じたら制限を解除する
dialog
要素を利用することで、最小限のマークアップとJavaScriptだけで、モーダルダイアログを作成できます。ひととおりの動作を確認したところで、開き方や閉じ方など基本的な使い方を順番に見ていきます。
開き方
dialog
要素は、デフォルトでは非表示になっています。表示方法は次の3種類があります。
- JavaScriptで
showModal()
メソッドを実行する - JavaScriptで
show()
メソッドを実行する - HTMLであらかじめ
open
属性を指定する(ページが読み込まれたらdialog
要素を表示する)
3種類のうち、showModal()
メソッドのみがdialog
要素をモーダルダイアログとして表示します。show()
メソッドまたはopen
属性で開くと、dialog
要素は非モーダルダイアログとして表示されます。非モーダルとは、画面に重ねて表示してもほかの操作を制限しないUIを指します。
「dialog
要素の使い方」の段落で紹介した作例では、showModal()
メソッドを実行してdialog
要素を表示しています。
const dialog = document.querySelector("dialog");
const showButton = document.querySelector("#showDialog");
showButton.addEventListener("click", () => {
dialog.showModal(); // dialog要素を開く
});
閉じ方
表示したdialog
要素を非表示にするには、次の方法が考えられます。
- JavaScriptで
close()
メソッドを実行する - ESCキーを押下するなど、ブラウザやOSが用意している閉じる操作を行う
dialog
要素には、何かしらの操作を行えるボタンが必要になります。操作のなかで要素を非表示にしたい場合はclose()
メソッドを実行します。次のコード例は、閉じるためのボタンを配置し、押下されたらclose()
メソッドが実行されます。
<dialog>
<button>閉じる</button>
</dialog>
const dialog = document.querySelector("dialog");
/* 表示する処理は省略 */
const button = document.querySelector("button");
button.addEventListener("click", () => {
dialog.close(); // dialog要素を閉じる
})
なお、close()
メソッドには文字列を引数として渡せて、returnValue
というプロパティから参照できます。詳しい使い方は次の段落で紹介します。
利用可能なイベント
dialog
要素で利用できる主なイベントは、次の2種類です。
close
:dialog
要素が閉じられるときに発火するcancel
:ブラウザやOSが用意している閉じる操作が指示されたときに発火する
2つのイベントは似ていますが、発火タイミングに違いがあることに注意してください。たとえば、close()
メソッドでdialog
要素が閉じられる場合は、close
イベントのみ発火します。それに対して、ESCキーの押下といった閉じる操作が行われた場合は、まずcancel
イベントが発火され、その後close
イベントが発火します。
また、close
イベントの引数event.target.returnValue
から、close()
メソッドの引数を参照できます。押下されたボタンに応じて、閉じたあとの処理を切り替えたいときに役立ちます。次のコード例は、dialog
要素にキャンセルと同意の2つのボタンを配置し、同意ボタンが押下されたときに追加の処理を行います。
<dialog>
<button id="disagree">キャンセル</button>
<button id="agree">同意する</button>
</dialog>
const dialog = document.querySelector("dialog");
// ⭐️closeイベントの追加
dialog.addEventListener("close", (event) => {
if(event.target.returnValue === "agree") {
// 同意するボタンが押下されたときの処理
}
})
// キャンセルボタンが押下されたとき
const disagreeButton = document.querySelector("#disagree");
disagreeButton.addEventListener("click", () => {
dialog.close("disagree"); // closeイベントに文字列 "disagree" を渡す
});
// 同意するボタンが押下されたとき
const agreeButton = document.querySelector("#agree");
agreeButton.addEventListener("click", () => {
dialog.close("agree"); // closeイベントに文字列 "agree" を渡す
});
※close()
メソッドに引数を渡さない場合や、ESCキーが押下されてclose
イベントが呼ばれる場合は、returnValue
プロパティは空文字(""
)を返します。
コラム:ほかの操作を制限する仕組み
showModal()
メソッドで表示されるモーダルダイアログは、Top layerと呼ばれる特別な要素として表示されます。Top layerとしてdialog
要素が表示されると、ほかの要素はクリックもフォーカスもできなくなり、ユーザーはダイアログボックスの操作に集中できます。なお、要素がTop layerとして表示されているかどうかは、Chromeの開発者ツールのからElements
パネルの#top-layer
から確認できます。
Top layerの詳細は、MDNの以下のページを参考にしてください。
closedby
属性
ここからはdialog
要素を利用するうえで便利なHTML属性を紹介します。dialog
要素とはサポート状況が少し異なるため、利用する際は注意してください。
dialog
要素にはclosedby
属性があり、モーダルの閉じやすさを調整できます。具体的には、ダイアログボックスの外側をクリックした際や、ESCキーを押下した際にモーダルを閉じるかどうかを制御できます。closedby
属性で設定できる値は次の通りです。
any
:ブラウザやOSの閉じる操作や、ダイアログボックスの外側を押下して閉じる(light dismissと呼ばれます)closerequest
:ブラウザやOSの閉じる操作で閉じるnone
:標準操作には応答せず、close()
メソッドでのみ閉じる(ESCキーでは閉じない)
なお、closedby
属性が未指定の場合、ブラウザやOSの閉じる操作で閉じられます。次の作例では、closedby
の各設定を動作確認できます。プルダウンメニューからclosedby
属性の値を変更できるので、試してみてください。
対応ブラウザ
closedby
属性は、Chrome 134・Edge 134(2025年3月)、Firefox 141(2025年7月)で利用可能です。
- 参照:Can I use…
autofocus
属性
標準の動作では、dialog
要素が表示されると最初にフォーカス可能な子要素にフォーカスが移動します。もしフォーカス対象の要素を変更したい場合は、autofocus
属性を使います。
次の作例は、規約の同意を確認するモーダルダイアログです。キャンセルと同意の2つボタンがあり、同意ボタンにautofocus
属性を指定しています。
<dialog>
<p>規約に同意しますか?</p>
<button>キャンセル</button>
<button autofocus>同意する</button>
</dialog>
要素の標準の動作であれば、キャンセルボタンにフォーカスが移動しますが、作例は同意ボタンにフォーカスが移動することを確認できます。
対応ブラウザ
autofocus
属性は、Chrome79・Edge 79(2020年1月)、Firefox 110(2023年2月)、macOS Safari 15.4(2022年3月)、iOS Safari 16.4(2023年3月)で利用可能です。
- 参照:Can I use…
※open
属性で非モーダルダイアログの<input autofocus />
をフォーカスした場合、2025年9月時点のiOS Safari 18.6では、仮想キーボードが表示されない仕様になっています。
dialog
要素にスタイルを適用する
モーダルダイアログを実装するときは、デザインにあわせて独自のスタイルを適用することが多いです。次の作例は、削除確認ダイアログを想定してdialog
要素にスタイルを適用しています。
独自のスタイルを適用する際は、次のポイントを押さえておくと実装がスムーズです。
- ダイアログボックスの外側に表示される半透明のオーバーレイは、
::backdrop
疑似要素でスタイルを調整できます。 - 開いた状態は、
dialog[open]
セレクターでスタイルを適用します。 - 開閉時にアニメーションを設定する場合、
dialog
要素が非表示のときはdisplay: none
となるため、アニメーション用の初期スタイルを@starting-style
で指定します。
コラム:背面がスクロールできる問題について
モーダルの一般的な実装として、モーダル表示中に背面にあるコンテンツをスクロールしないようにする制御が必要となることが多いです。改善策として、dialog
要素を開いているときはルート要素のスクロールをoverflow
プロパティで抑制するといった方法が考えられます。
:root:has(dialog[open]) {
overflow: hidden;
scrollbar-gutter: stable;
}
※2025年9月時点では、上述したコードでもiOS Safari 18.6で完全に制御するのが難しいです。
まとめ
dialog
要素の基本的な使い方を紹介しました。dialog
要素を利用することで、標準の機能でシンプルにモーダルダイアログを実装できます。また、本記事では紹介しませんでしたが、以下の関連機能があり今後サポートされることが期待されます。
- Invoker Commands API:
command
・commandfor
属性を利用して、JavaScriptなしでdialog
要素の開閉が行える - CloseWatcher API:ブラウザやOSの閉じる動作を制御する。ESCキーが押下されたら
dialog
要素を本当に閉じるかどうかを確認できる- 参考リンク:Close Watcher API - MDN
関連機能はサポート時期が新しいものが多く、場合によってはdialog
要素を使用しづらいかもしれません。ですが、dialog
要素の登場以前に必要だった複雑な制御を考えると、dialog
要素を使用するメリットは十分にあると思います。
dialog
要素の採用が難しい場合は、まずは独自の実装は避けてUIライブラリの利用を検討するとよいでしょう。UIライブラリの特徴や選び方については、記事『ウェブ制作にも便利!React & Vueで始めるヘッドレスUI』も参考にしてみてください。
参考記事
dialog
要素全般- closedby属性
- autofocus属性