アカウント削除や決済確定など、取り返しのつかない(不可逆な)アクションを実行する直前に、ユーザーへ重大な結果を警告し、最終確認を強制するためのコンポーネント。
この記事を読むと、標準のDialog(ダイアログ)との使い分けと、安全性を担保する設計・A11y要件が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
ユーザーのアクションによって重大かつ不可逆な結果(データの削除やプラン変更など)が生じる前に、最終確認を行う特殊なダイアログ。
Dialog(標準)との違い:標準のDialogが「情報の追加・編集」など安全な操作にも使われるのに対し、AlertDialogは原則として破壊的・不可逆・重大な結果を伴う操作の直前に限定して使用する。また、A11y的にもスクリーンリーダーでの読み上げの緊急度が上がる。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- アカウント退会、プロジェクトの完全削除など、あとから元に戻せない(Undoできない)破壊的操作
- 決済の確定、高額なプランへの変更など、ユーザーに金銭的・法的な重大な影響がある操作
- 保存していない作業内容がすべて失われる可能性がある画面遷移の警告
3.2 When NOT to use
- 名前などの簡単な「設定の保存」完了(単にToastでよい)
- 元に戻せる操作や、「非公開にする」などの状態変更(標準Dialogでよい)
- 単にユーザーに同意チェックボックスを押させたいだけの長文の規約(標準Dialogか単独ページにするべき)
3.3 代替UI(Alternatives)
- 通常の設定変更や同意 →
Dialog - 元に戻せる操作 →
Toast(に「元に戻す(Undo)」ボタンを付ける)
4. 設計判断の核(Decision Principles)
「意図しない誤クリック」をゼロにする。
判断の優先順位:① 役割の明確化(本当に不可逆か?) → ② アクションの安全性(Cancelが主役) → ③ 強制力(外を暗転+ロック)
- AlertDialogはユーザーの作業を「強い力で止める」ため、無用な確認ダイアログの乱発(OKボタンを押すだけの儀式)を避けることが最も重要。
5. 状態設計(States)
5.1 必須状態(Required)
- Default:画面中央に表示され、背景が暗転(Scrim)して背景の操作が完全にロックされた状態
- Focus Trap:Tabキーがダイアログ内だけでループする状態。開いた瞬間、自動フォーカスは安全な選択肢(キャンセル)に当たる
5.2 条件付き状態(Conditional)
- Loading(処理中):削除ボタンを押下後、通信中に非同期処理が行われている状態(ボタンがスピナーになる等)。この間はCancelすら押せなくする(またはCancelで中断できるようにする)
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Default | ✅ | 最も重要な警告が出ていること、他の操作は一切できないこと |
| Focus Trap (Cancel auto-focus) | ✅ | 操作を誤って実行(Enter連打等)しないよう守られていること |
| Loading | — | 破壊的処理が実行中であり、ブラウザを閉じないでほしいこと |
6. バリエーション設計(Variants)
AlertDialogは目的が単一であるため、過度なバリエーションを持たせない。
| バリアント | 目的 |
|---|---|
| Destructive Alert | (赤色)完全削除など、破壊的であることを視覚的にも強く訴える |
| Warning Alert | (オレンジ等)決済や影響度の大きい変更。注意喚起が目的 |
禁止パターン:AlertDialogの中に画像や複雑なフォーム(長文のテキストエリア)を含めること。目的の「警告と確認」への集中を削ぐため。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- OKボタンの連打誘発:開いた瞬間の自動フォーカスが「削除(OK)」に当たっており、ユーザーがEnterを連打した事故でデータが消える
- タイトルの曖昧さ:「確認」「本当によろしいですか?」など、タイトルだけ読んでも何が起きるか分からない
- 背景クリックで消える:重要度が高い警告なのに、誤って背景領域(Scrim)をクリックしただけでフッと消えてしまう
7.1 Bad(典型3つ)
- タイトルが「警告」だけで、ボタンが「はい」「いいえ」になっている(「はい」が何を意味するのか分からない)
- 削除ボタン(Destructive)が右、キャンセルが左にありながら、自動フォーカスが右の削除ボタンに当たっている
- 取るに足らない設定の変更(通知設定のON/OFFなど)にまで「変更を保存しますか?」といちいちAlertDialogを出す
7.2 Good(対になる3つ)
- タイトルが直感的な動詞「[オブジェクト]を削除しますか?」であり、ボタンラベルも「削除する」「今回はしない」と明確である
- ダイアログが開いた瞬間の初期フォーカス(autoFocus)が安全な選択肢(キャンセル)に当たっている
- 取り返しのつく操作にはToast(元に戻すボタン付)等を使い、AlertDialogは「本当にヤバい時」だけに温存されている
7.3 How to fix(手順)
- アクションが本当に不可逆(Undo不可能)か確認し、可能ならToastへ変更する
- タイトルは「[オブジェクト名] を [動詞] しますか?」と具体的に書く
- アクションボタンのラベル(テキスト)を動詞にする(×「はい」 ○「プロジェクトを削除する」)
- 初期フォーカス(
autoFocus)を「キャンセル(安全な方)」のボタンへ意図的に設定する - 誤ってダイアログを閉じて事態を悪化させないため、背景(Overlay)クリックでの
dismissを無効化する
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
Escキーでダイアログをキャンセル(閉じる)ことができる- フォーカストラップ:
Tabキー移動がダイアログ内でのみループする
Focus
- ダイアログが開いた瞬間、 キャンセル(または最も安全な操作)ボタンに自動でフォーカスを移す
- ダイアログが閉じた後は、ダイアログを開くトリガーとなった元のボタンへフォーカスを戻す
Screen Reader
- コンテナには、標準ダイアログ(
role="dialog")よりも緊急度の高いrole="alertdialog"を指定する - これにより、スクリーンリーダーは現在読み上げている内容を中断してでも、直ちにこの警告テキストをユーザーに伝える
aria-labelledbyでタイトルを、aria-describedbyで警告の詳細文を必ず紐づける
Touch / Pointer
- (Mustでも述べた通り)誤操作を防ぐため、AlertDialogにおいては背景オーバーレイタップでのDismiss(閉じる)挙動を一般的に無効化すべきである
Contrast / Readability
- Destructive(破壊的操作)を示す赤いボタンは、文字とのコントラスト比(4.5:1以上)に注意する
10. 実装メモ(Implementation Notes)
radix-uiやshadcn/uiなどのモダンなHeadless UIライブラリでは、Dialogとは別にAlertDialogコンポーネントが用意されていることが多い。これらは最初からrole="alertdialog"や背景クリック無効化が実装済みであるため積極的な利用を推奨する- ボタンの配置について、iOS/Macの標準(キャンセルが左/下が多め)やWindows/Androidの標準(OKが右/上が多め)という宗教論争があるが、Webにおいては「行動文脈(次へ進む=右、戻る=左)」に従い 左:Cancel / 右:Destructive(Action) とする並びが現在主流である
11. 関連リンク
- 関連するUIデザイン原則: エラーの予防 (Error Prevention), 明瞭性と確実性 (Clarity & Certainty), フィードバック (Feedback)
- 用語集(定義): アクセシビリティ (Accessibility)
- 関連するUIコンポーネント(横): Toast(トースト通知)
12. まとめ
AlertDialog(警告ダイアログ)の目的は「ユーザーの暴走を安全かつ確実に止めること」に尽きます。ただの確認画面ではなく、初期フォーカスの位置や背景クリック挙動など、「ついうっかり」を許さない強固な設計(role="alertdialog")を施すことで、取り返しのつかない事故からユーザーを守ることができます。