サイトアイコンmaita tomoya dev io

#90 WAI-ARIA APG パターン比較: status / alert / tooltip の使い分け

はじめに

Webアプリケーションでユーザーに情報を伝える場面は多い。「保存しました」「エラーです」「このボタンは○○です」——これらは視覚的には実装できていても、スクリーンリーダー利用者に適切に伝わっているだろうか。

WAI-ARIA APG(Authoring Practices Guide)では、通知系のパターンとして statusalerttooltip の3つを定義している。本記事ではそれぞれの違いと使い分けを整理する。


3パターンの比較表

項目statusalerttooltip
目的控えめな通知緊急の通知補足説明
role属性statusalerttooltip
aria-live(暗黙値)politeassertiveなし
aria-atomic(暗黙値)truetrue-
フォーカス移動しないしないしない
表示トリガーDOM変更DOM変更フォーカス/ホバー
自動消去NGNGホバー/フォーカス外れで消える

最大の違いは aria-live の値 である。これがスクリーンリーダーの読み上げタイミングを決定する。


status(role="status")

ユーザーの作業を中断せずに、状態の変化を控えめに伝えるパターン。

暗黙のプロパティ

  • aria-live="polite" — スクリーンリーダーは現在の読み上げを終えてから通知する
  • aria-atomic="true" — 変更部分だけでなくコンテナ全体を読み上げる

ユースケース

  • 検索結果件数の更新
  • フォームの保存完了メッセージ
  • ショッピングカートの合計金額更新
  • ファイルアップロード進捗

実装例

<div role="status">5件の結果が見つかりました</div>

HTML5の <output> 要素は暗黙的に role="status" を持つ。

<output>計算結果: 42</output>

注意点

  • 自動的に消えるメッセージにしてはいけない(WCAG 2.2.3 違反)
  • ページロード時に既に存在する status は読み上げられない。動的に変更されたもののみ対象

alert(role="alert")

緊急性の高い情報を即座にユーザーに伝えるパターン。

暗黙のプロパティ

  • aria-live="assertive" — 現在の読み上げを中断して即座に通知する
  • aria-atomic="true"

ユースケース

  • バリデーションエラー
  • ネットワーク接続の切断
  • セッションタイムアウト警告
  • 重要なシステムメッセージ

実装例

<div role="alert">メールアドレスの形式が正しくありません</div>

注意点

  • フォーカスは移動しない(フォーカスを移動させたい場合は alertdialog を使う)
  • 頻繁に発火させるとユーザー体験を著しく損なう(WCAG 2.2.4)
  • こちらも自動消去NG

alert と alertdialog の違い

alertalertdialog
フォーカス移動なしダイアログに移動
ユーザーの応答不要必要(確認ボタン等)
モーダルNoYes

「エラーがあります」と伝えるだけなら alert。「本当に削除しますか?」のように応答が必要なら alertdialog を使う。


tooltip(role="tooltip")

要素に対する補足情報をポップアップで表示するパターン。

特徴

  • ライブリージョンではない(aria-live なし)
  • スクリーンリーダーはトリガー要素にフォーカスした時点で aria-describedby 経由で読み上げる
  • フォーカスまたはホバーで表示、Escape で閉じる

実装例

<button aria-describedby="save-tip">💾</button>
<div role="tooltip" id="save-tip">ファイルを保存する</div>

キーボード操作

  • Escape: ツールチップを閉じる
  • フォーカスがトリガー上にある間は表示維持
  • フォーカスが外れると非表示

注意点

  • tooltip内にリンクやボタンなどフォーカス可能な要素を入れてはいけない
  • フォーカス可能な内容が必要な場合は non-modal dialog を使う
  • APG公式ではまだ「work in progress」(正式な実装例なし)

使い分けフローチャート

ユーザーに情報を伝えたい
  │
  ├── ユーザーの応答が必要?
  │     └── Yes → alertdialog(モーダル)
  │
  ├── 緊急性が高い?(エラー、警告)
  │     └── Yes → alert
  │
  ├── 状態変化の通知?(保存完了、件数更新)
  │     └── Yes → status
  │
  └── 要素の補足説明?(アイコンの意味、入力ヒント)
        └── Yes → tooltip

よくある誤り

誤り問題正しい実装
保存完了に role="alert"緊急ではないのに読み上げを中断するrole="status" を使う
エラーメッセージに role なしスクリーンリーダーに通知されないrole="alert" を付ける
tooltip 内にリンクを配置フォーカス不可能で操作できないnon-modal dialog にする
aria-live="polite" を明示的に書く冗長(status は暗黙で持つ)role だけ指定すれば十分
通知を3秒後に自動消去WCAG 2.2.3 違反消去しないか、ユーザー操作で消す

aria-live の値と挙動まとめ

挙動対応 role
off通知しない(デフォルト)-
politeアイドル時に読み上げstatus, log
assertive即座に割り込み読み上げalert

aria-live を直接指定するのではなく、適切な role を使うことで暗黙的に設定されるのがベストプラクティスである。


まとめ

  • status: 控えめ。ユーザーの手が空いたら伝える。保存完了や件数更新に最適
  • alert: 緊急。今すぐ伝える。エラーや警告に限定して使う
  • tooltip: 通知ではない。要素の補足説明。aria-describedby で紐付ける

3つともフォーカスを移動しない点は共通している。フォーカス移動が必要なら alertdialogdialog を検討する。


デモ(CodePenで試す)

以下の「Edit on CodePen」ボタンをクリックすると、CodePen上でコードを編集・実行できる。スクリーンリーダー(macOSならVoiceOver: Cmd+F5)を有効にして動作の違いを体感してほしい。

Demo 1: role="status" — 保存完了通知

Demo 2: role="alert" — バリデーションエラー

Demo 3: role="tooltip" — アイコンの補足説明


参考