2026年8月27日

2026年8月27日

WordPressでモーダルダイアログを実装する方法|dialog要素と子テーマで作る

モーダルダイアログは、ページの上に重ねて表示し、閉じるまで背景を操作できなくする UI です。お知らせ、画像の詳細、確認メッセージなどに使えます。

以前は div を display: none で隠しておき、JavaScript で表示を切り替える作り方が一般的でした。しかしその方法では、Esc キーで閉じる、キーボードのフォーカスをダイアログの中に留める、背景をスクリーンリーダーから隠す、といった処理をすべて自分で書く必要があります。現在は HTML の <dialog> 要素を使えば、これらをブラウザーが受け持ちます。<dialog> は 2022年3月から主要ブラウザーで広く使える状態(Baseline)になっています。

この記事では、WordPress の子テーマに CSS と JavaScript を追加し、ブロックエディターの「カスタム HTML」ブロックにダイアログを置く方法を説明します(2026年10月時点の WordPress 6.9 で確認した内容です)。

dialog 要素の基本

<dialog> には開き方が 2 つあります。

開き方 動作
dialog.showModal() モーダルとして開く。ダイアログの外側は操作できなくなり(inert)、Esc キーで閉じられる。背景は ::backdrop で装飾できる
dialog.show() モーダルでない形で開く。背景も操作でき、Esc キーでは閉じない

この記事ではモーダルにしたいので showModal() を使います。閉じるには次の方法があります。

  • JavaScript で dialog.close() を呼ぶ
  • ダイアログ内の <form method="dialog"> を送信する(サーバーには送信されず、ダイアログが閉じる)
  • モーダルとして開いている場合は Esc キー

showModal() で開くと、フォーカスはダイアログ内の最初のフォーカスできる要素に移ります。特定の要素にフォーカスさせたい場合は、その要素に autofocus 属性を付けます。

作るもの

  • ボタンを押すとダイアログが開く
  • 「閉じる」ボタン、Esc キー、背景のクリックで閉じる
  • 開いている間はページ本体がスクロールしない
  • 1 ページに複数のダイアログを置ける

ファイル構成は次のとおりです(子テーマのフォルダー名は例です)。

wp-content/themes/my-child-theme/
├── functions.php
└── assets/
    ├── modal.css
    └── modal.js

テーマのファイルを直接編集すると、テーマの更新で上書きされて消えます。子テーマが無い場合は先に作成してください。手順は「WordPressで子テーマを作成する方法」で説明しています。

手順

1. CSS を作る

assets/modal.css を作成します。

/* ダイアログ本体。余白は内側の要素に付ける(理由は手順3) */
.my-modal {
	padding: 0;
	border: none;
	border-radius: 8px;
	width: min(90vw, 560px);
	max-height: 85vh;
	box-shadow: 0 10px 30px rgb(0 0 0 / 0.3);
}

.my-modal__body {
	padding: 24px;
}

/* 背景の暗い幕 */
.my-modal::backdrop {
	background: rgb(0 0 0 / 0.5);
}

.my-modal__close {
	margin-top: 16px;
	cursor: pointer;
}

/* 開いている間はページ本体をスクロールさせない */
body:has(dialog.my-modal[open]) {
	overflow: hidden;
}

/* 開くときの軽いアニメーション */
.my-modal[open] {
	animation: my-modal-in 0.2s ease-out;
}

@keyframes my-modal-in {
	from {
		opacity: 0;
		transform: translateY(8px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

/* 動きを減らす設定の利用者にはアニメーションしない */
@media (prefers-reduced-motion: reduce) {
	.my-modal[open] {
		animation: none;
	}
}

モーダルとして開いた <dialog> は、ブラウザーの標準スタイルで画面の中央に配置されます。位置を指定する CSS は不要です。

2. JavaScript を作る

assets/modal.js を作成します。ページ全体のクリックを 1 か所で受け取る書き方にしているので、ダイアログやボタンが何個あっても同じコードで動きます。

document.addEventListener('click', function (event) {
	// data-modal-open="ダイアログのid" を持つボタンで開く
	const opener = event.target.closest('[data-modal-open]');
	if (opener) {
		const dialog = document.getElementById(opener.dataset.modalOpen);
		if (dialog && typeof dialog.showModal === 'function') {
			dialog.showModal();
		}
		return;
	}

	// 背景(::backdrop)のクリックは dialog 要素自身へのクリックとして届く
	if (event.target instanceof HTMLDialogElement && event.target.open) {
		event.target.close();
	}
});

3. 背景クリックで閉じる仕組み

::backdrop は <dialog> 要素の一部として扱われるため、背景をクリックすると event.target が <dialog> 自身になります。一方、ダイアログの中身をクリックしたときは、内側の要素(.my-modal__body やその子)が event.target になります。

手順1の CSS で <dialog> の padding を 0 にし、余白を内側の .my-modal__body に付けたのはこのためです。<dialog> 自体に余白があると、余白部分のクリックも「背景のクリック」と判定され、ダイアログが閉じてしまいます。

背景クリックで閉じたくない場合(入力フォームなど、誤って閉じると困るもの)は、2 つ目の if ブロックを削除してください。Esc キーと「閉じる」ボタンでは閉じられます。

4. functions.php で読み込む

子テーマの functions.php に追加します。WordPress 6.3 以降は、wp_enqueue_script() の 5 番目の引数に配列を渡して defer を指定できます。

<?php
// 子テーマの functions.php に追加する
add_action( 'wp_enqueue_scripts', function () {
	$dir = get_stylesheet_directory();
	$uri = get_stylesheet_directory_uri();

	wp_enqueue_style(
		'my-modal',
		$uri . '/assets/modal.css',
		array(),
		filemtime( $dir . '/assets/modal.css' )
	);

	wp_enqueue_script(
		'my-modal',
		$uri . '/assets/modal.js',
		array(),
		filemtime( $dir . '/assets/modal.js' ),
		array(
			'strategy'  => 'defer',
			'in_footer' => true,
		)
	);
} );

すでに functions.php の先頭に <?php がある場合は、2 行目以降だけを追加します。バージョンにファイルの更新日時(filemtime())を使っているので、CSS や JavaScript を編集するとブラウザーのキャッシュが自動で切り替わります。

特定のページだけで読み込みたい場合は、関数の最初に条件を足します。

<?php
add_action( 'wp_enqueue_scripts', function () {
	// 固定ページ「contact」以外では読み込まない
	if ( ! is_page( 'contact' ) ) {
		return;
	}
	// ...手順4の wp_enqueue_style / wp_enqueue_script をここに書く...
} );

wp_enqueue_scripts の引数の詳細は「wp_enqueue_scriptsでJSとCSSを読み込む方法」を参照してください。

5. ダイアログの HTML を置く

ダイアログを表示したい投稿や固定ページを編集し、「カスタム HTML」ブロックを追加して次の HTML を貼り付けます。

<button type="button" class="wp-element-button" data-modal-open="info-modal">詳しく見る</button>

<dialog id="info-modal" class="my-modal" aria-labelledby="info-modal-title">
	<div class="my-modal__body">
		<h2 id="info-modal-title">お知らせ</h2>
		<p>ここに表示したい内容を書きます。</p>
		<form method="dialog">
			<button type="submit" class="my-modal__close">閉じる</button>
		</form>
	</div>
</dialog>
  • ボタンの data-modal-open の値と、<dialog> の id を一致させます。
  • 同じページに複数置く場合は、id(と aria-labelledby・見出しの id)をダイアログごとに別の値にします。
  • wp-element-button は、ブロックテーマのボタンのスタイルを当てるためのクラスです。不要なら外してかまいません。
  • aria-labelledby で見出しを指定すると、スクリーンリーダーがダイアログの名前として読み上げます。
  • <dialog> 要素自体には tabindex を付けないでください。

WordPress は、投稿に保存する HTML を利用者の権限で絞り込みます。単一サイトの管理者と編集者は unfiltered_html 権限を持つため、そのまま保存されます。投稿者などそれ以外の権限で保存すると、一部のタグや属性が取り除かれることがあります。

6. 動作を確かめる

公開したページで次の点を確認します。

  1. ボタンを押すとダイアログが開き、背景が暗くなる
  2. 「閉じる」ボタン、Esc キー、背景のクリックで閉じる
  3. 開いている間、Tab キーでダイアログの外にフォーカスが出ない
  4. ダイアログの中身(文字や余白)をクリックしても閉じない
  5. スマートフォンの幅でも画面からはみ出さない

開かない場合は、ブラウザーの開発者ツール(F12)の「Console」でエラーを、「Network」で modal.js と modal.css が読み込まれているか(404 になっていないか)を確認します。キャッシュ系プラグインを使っている場合は、キャッシュを削除してから確認してください。

注意点

  • ページを開いた直後に自動で表示しない: 読み込みと同時に本文を覆うダイアログは、読者の邪魔になりやすい表示です。この記事のように、読者がボタンを押したときに開く使い方が基本です。
  • 閉じる手段を見える形で用意する: Esc キーを使えない利用者もいるため、画面に「閉じる」ボタンを置きます。
  • フォームを入れる場合: ダイアログ内のフォームから情報を送る場合、サーバー側での入力値の検証やエスケープは通常のフォームと同じく必要です。お問い合わせフォームなどはフォーム用のプラグインで作り、そのショートコードを含むブロックをダイアログの中に置く方法もあります。
  • ポップアップ用プラグインとの違い: 表示のタイミング(スクロール量・離脱時)や表示回数の制御が必要なら、専用のプラグインを使うほうが早いことがあります。比較は「WordPressでポップアップを実装する方法」を参照してください。

まとめ

  • モーダルダイアログは HTML の <dialog> と showModal() で作ると、Esc キーでの終了や背景の操作無効化をブラウザーが受け持ちます。
  • CSS と JavaScript は子テーマに置き、functions.php の wp_enqueue_scripts で読み込みます。
  • ダイアログの HTML は「カスタム HTML」ブロックに置き、ボタンの data-modal-open と id を一致させます。
  • 背景クリックで閉じる処理は、<dialog> の padding を 0 にして中身を内側の要素で包むと誤判定しません。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲