【JS応用|実務向け】実務で差がつくFocusEvent活用術:アクセシビリティとUXを両立するフォーカス制御

1. 導入:なぜFocusEventが重要なのか

現代のWebアプリケーションにおいて、キーボード操作やスクリーンリーダーによるナビゲーションは必須です。特にReactやVueなどのSPA(シングルページアプリケーション)では、画面遷移やモーダルの開閉時に「フォーカスをどこに置くか」がUXの良し悪しを決定します。FocusEventを正しく扱うことで、ユーザーの迷いを減らし、アクセシビリティ基準(WCAG)を満たす堅牢なインターフェースを実現できます。

2. 基礎知識:フォーカス関連イベントの仕組み

FocusEventには主に以下の4つの種類があります。これらを混同しないことが実装の第一歩です。
・focus: 要素にフォーカスが当たった瞬間に発生(バブリングしない)。
・blur: 要素からフォーカスが外れた瞬間に発生(バブリングしない)。
・focusin: 要素またはその子孫要素にフォーカスが当たった時に発生(バブリングする)。
・focusout: 要素またはその子孫要素からフォーカスが外れた時に発生(バブリングする)。

実務では、親コンテナで一括管理したい場合はバブリングする「focusin/focusout」を、特定の要素の状態だけを見たい場合は「focus/blur」を選択するのが定石です。

3. 実装・解決策:モーダル内フォーカス閉じ込め

モーダルを開いた際、フォーカスがモーダルの外に漏れてしまうと、スクリーンリーダー利用者は操作が困難になります。focusoutイベントを監視し、フォーカスがモーダル外へ移動しそうになったら強制的にモーダル内へ戻す仕組みが有効です。

4. サンプルプログラム:フォーカスをモーダル内に制御する例

このコードは、フォーカスがモーダルから外れそうになった場合に、強制的に先頭要素へ戻す簡易的な実装です。

// モーダル要素を取得
const modal = document.querySelector('.modal');

// focusoutイベントを監視(バブリングを利用)
modal.addEventListener('focusout', (event) => {
  // フォーカスが移動した先の要素(relatedTarget)がモーダル外か判定
  if (!modal.contains(event.relatedTarget)) {
    console.log('フォーカスがモーダル外へ出ました。先頭に戻します。');
    
    // モーダル内の最初のフォーカス可能要素へ強制移動
    const firstFocusable = modal.querySelector('button, [href], input, select, textarea');
    if (firstFocusable) {
      firstFocusable.focus();
    }
  }
});

5. 応用・注意点:現場で陥りやすいバグの回避策

1. relatedTargetの確認: focusoutイベントで「次にどこにフォーカスが移るか」を知るには、event.relatedTargetが必須です。これがnullの場合(ブラウザ外へのクリックなど)、無理に制御を行うと予期せぬ挙動になるため、nullチェックを必ず入れましょう。
2. 要素の表示・非表示: display: none の要素に .focus() を実行してもフォーカスは当たりません。tabindex=”-1″ を付与した要素に対してプログラムからフォーカスを当てる手法が、アクセシビリティ対応の現場では一般的です。
3. ブラウザの差異: focus/blurイベントはバブリングしませんが、focusin/focusoutはバブリングします。ライブラリ開発や汎用コンポーネント作成時は、イベントの伝播特性を意識した実装を心がけてください。

タイトルとURLをコピーしました