通知・ダイアログ
アラートダイアログ
解説ありAlert and Message Dialogs
「本当に削除しますか?」など、ユーザーの確認・応答を求めるダイアログ。
アラートダイアログ(role="alertdialog")とは?
アラートダイアログは、「本当に削除しますか?」のような重要な確認や警告を出し、ユーザーの返答を待つモーダルです。 通常のダイアログとの違いは、メッセージ自体が緊急で重要だという点を 支援技術に明示することにあります。
ネイティブ <dialog> に role="alertdialog" を付けてshowModal() で開けば、モーダルの面倒な部分(フォーカス管理・Esc・背面 inert)を 活かしつつ、「これは確認の警告である」と伝えられます。
なぜアクセシビリティが大事なの?
- スクリーンリーダー利用者に、開いた瞬間 「アカウントを削除しますか? この操作は取り消せません」というタイトルと説明をまとめて読み上げる必要があります。
aria-labelledbyとaria-describedbyがそれを担います。 - 取り返しのつかない操作なので、初期フォーカスは安全側(キャンセル)に置きます。 うっかり Enter を押しても破壊的な動作が起きないようにするためです。
- Esc でいつでも安全に離脱でき、閉じたあとは元のボタンへ戻ることで 操作の文脈を失いません。
ライブデモ(推奨実装)
下の「アカウントを削除」を押すと確認ダイアログが開きます。 開いた直後にフォーカスが「キャンセル」に当たっていることを確認してください。
試してみよう:Enter で開く → 初期フォーカスは「キャンセル」 → Tab で「削除する」へ移動できる → Esc で閉じる → フォーカスが元のボタンへ戻る。
ポイント
スクリーンリーダーでは、開いた瞬間に「アカウントを削除しますか? この操作は取り消せません…, アラート, ダイアログ」のようにタイトルと説明がまとめて読み上げられます。これがaria-labelledby + aria-describedby の効果です。
キーボード操作
| キー | 動作 | 必須/任意 |
|---|---|---|
| Esc | ダイアログを閉じる(=キャンセル扱い。showModal() なら標準対応) | 必須 |
| Tab / Shift+Tab | ボタン間を循環移動(ダイアログ内に閉じ込められる) | 必須 |
| Enter / Space | フォーカス中のボタンを実行 | 必須 |
| (開いた直後) | 初期フォーカスは安全側(キャンセル)のボタンに置く | 必須(推奨の置き方) |
必要な WAI-ARIA / ロール
| 付ける場所 | 属性 / ロール | 意味 |
|---|---|---|
| ダイアログ本体 | role="alertdialog" | 「重要な確認・警告のダイアログ」であることを伝える。 |
| ダイアログ本体 | aria-modal="true" | 背面が操作不可のモーダルであることを明示(role を上書きしたため明示する)。 |
| ダイアログ本体 | aria-labelledby="タイトルのid" | ダイアログの名前(質問文)を指す。 |
| ダイアログ本体 | aria-describedby="説明のid" | 結果の重大さを説明する本文を関連付け、開いた瞬間に読み上げさせる。 |
| キャンセルボタン | autofocus | 初期フォーカスを安全側に置く。 |
実装:推奨パターン(Good)
良い例 / 推奨
ネイティブ <dialog> に role="alertdialog" を付け、タイトルと説明を関連付ける。初期フォーカスはキャンセル。
マークアップ:
<button type="button" id="delete">アカウントを削除</button>
<dialog id="confirm"
role="alertdialog"
aria-modal="true"
aria-labelledby="confirm-title"
aria-describedby="confirm-desc">
<h2 id="confirm-title">アカウントを削除しますか?</h2>
<p id="confirm-desc">
この操作は取り消せません。すべてのデータが失われます。
</p>
<!-- 初期フォーカスは「安全側」のキャンセルに置く -->
<button type="button" id="cancel" autofocus>キャンセル</button>
<button type="button" id="confirm-ok">削除する</button>
</dialog>開閉のスクリプト:
const dialog = document.getElementById('confirm');
const openBtn = document.getElementById('delete');
const cancelBtn = document.getElementById('cancel');
const okBtn = document.getElementById('confirm-ok');
openBtn.addEventListener('click', () => dialog.showModal());
cancelBtn.addEventListener('click', () => dialog.close());
okBtn.addEventListener('click', () => {
dialog.close();
// …削除処理…
});
// showModal() なら Esc で閉じ、閉じると delete ボタンへ戻る。補足
role="alertdialog" を付けると <dialog> 既定の role="dialog" を 上書きします。モーダル性が暗黙に伝わらなくなる場合があるため、aria-modal="true" も合わせて明示しておくのが安全です。
アンチパターン(Bad)
下は window.confirm 風に <div> で作った確認ボックスです。マウスでは選べますが、開いても読み上げられず、フォーカスも移らず、Esc でも閉じられません。
アカウントを削除しますか?
試してみよう:開いてもスクリーンリーダーは何も読み上げない。Tab で背面に抜ける。Esc で閉じない。「はい/いいえ」は span なのでキーボードで選べない。
<!-- ❌ window.confirm 風の自作 div -->
<button type="button" onclick="showConfirm()">アカウントを削除</button>
<div id="box" class="box" style="display:none">
<p>アカウントを削除しますか?</p>
<span onclick="hide()">いいえ</span>
<span onclick="doDelete()">はい</span>
</div>
<!-- role 無し・フォーカス移動無し・Esc 無し・閉じる手段が span -->悪い例 / 避ける
この実装の問題点:
- 読み上げられない —
role="alertdialog"もaria-describedbyも無く、何の確認か伝わらない。 - フォーカスが移らない — 開いてもボックスに入らず、背面に Tab で抜けてしまう。
- Esc で閉じない — 安全な離脱手段が無い。
- 選択肢が
<span>— フォーカスできず、キーボードで「はい/いいえ」を選べない。 - 危険な操作の防御が無い — 初期フォーカスや安全側の配慮がない。
ポイント
取り返しのつかない操作ほど、読み上げ・フォーカス・安全な初期フォーカス・Esc が重要です。<dialog role="alertdialog"> なら、その土台を簡単に整えられます。
実装チェックリスト
- ネイティブ
<dialog>+showModal()を使っている role="alertdialog"とaria-modal="true"を付けているaria-labelledbyで質問文、aria-describedbyで結果の説明を関連付けている- 初期フォーカスを安全側(キャンセル)に置いている
- Tab がダイアログ内を循環し、背面に漏れない
- Esc で閉じられる
- 閉じると開いたトリガーへフォーカスが戻る
- フォーカスリングを消していない
原文(英語):Alert and Message Dialogs Pattern — W3C APG(新しいタブで開きます)