【実務・中級編】リストアイテムの選択状態管理 – HTML実践ガイド

リストの「選択」を極める:aria-selected を用いたアクセシブルな状態管理のベストプラクティス

現場でフロントエンドを書いていると、「ただのリスト」に機能を持たせる場面に多々遭遇します。ドロップダウンの選択肢、タブ切り替え、あるいは複数選択可能なチェックリスト。これらを実装する際、`class=”is-selected”` を付与して終わりにしていないでしょうか?

もしあなたが「動けばいい」以上のクオリティを求めているなら、WAI-ARIAの仕様に立ち返る必要があります。特に `aria-selected` を適切に扱うことは、アクセシビリティの向上だけでなく、UIの状態をプログラムから「解釈可能」にするという、堅牢なフロントエンド開発の第一歩です。

今日は、中級エンジニアが避けては通れない「リストアイテムの選択状態管理」について、ブラウザの裏側まで含めて深掘りしていきます。

—

なぜ `aria-selected` が必要なのか?

まず前提として、HTMLの標準要素である `

    ` や `

  • ` には、デフォルトでは「選択状態」という概念はありません。単なる箇条書きのコンテナに過ぎないからです。

    ここに `aria-selected=”true/false”` を付与することで、支援技術(スクリーンリーダーなど)に対して、「この項目は現在選択されており、対話的な操作が可能である」という強いメタデータを伝えることができます。

    ブラウザのアクセシビリティツリー上で、この属性がどう振る舞うかを理解しておきましょう。`aria-selected` を検知したブラウザは、要素の役割(Role)に基づいて、「選択されている項目がリストの中にいくつあるか」を計算し、ユーザーに読み上げます。これを怠ると、視覚障害を持つユーザーは「今、自分がどこを選んでいるのか」を正確に把握できなくなります。

    —

    実践:堅牢な単一/複数選択リストの実装

    現場でそのまま使える、状態管理の基本パターンを紹介します。ポイントは、DOMの状態とJavaScriptの論理モデルを分離しつつ、確実に属性を同期させることです。

    /

    • 選択状態を管理するクラス(シンプルかつ拡張性重視)

    /
    class SelectionManager {
    constructor(containerElement, isMultiple = false) {
    this.container = containerElement;
    this.isMultiple = isMultiple;
    this.items = Array.from(this.container.querySelectorAll(‘[role=”option”]’));

    this.init();
    }

    init() {
    this.container.addEventListener(‘click’, (e) => {
    const target = e.target.closest(‘[role=”option”]’);
    if (!target) return;

    this.toggleSelection(target);
    });
    }

    toggleSelection(target) {
    const isSelected = target.getAttribute(‘aria-selected’) === ‘true’;

    if (!this.isMultiple) {
    // 単一選択の場合は、他のすべての選択を解除する
    this.items.forEach(item => item.setAttribute(‘aria-selected’, ‘false’));
    target.setAttribute(‘aria-selected’, ‘true’);
    } else {
    // 複数選択の場合は、トグルする
    target.setAttribute(‘aria-selected’, (!isSelected).toString());
    }
    }
    }

    // 使い方:
    //

      //

    • Option 1
    • //

    • Option 2
    • //

    注意すべきポイント

    • `role=”option”` の指定: `aria-selected` は、`listbox` などの適切なコンテナ(`role=”listbox”`)の配下にある `role=”option”` に対して適用するのが仕様上の正解です。
    • キーボード操作: 上記コードはクリックイベントのみですが、実務では `ArrowDown`/`ArrowUp` によるフォーカス移動と `Space`/`Enter` による選択確定の実装が必須です。これができて初めて「プロのUI」と言えます。

    —

    現場のリアル:状態の「同期」でハマらないために

    ここでよくある罠が、「JavaScriptで状態を更新したのに、スタイルが追従しない」、あるいはその逆です。

    CSS側では、クラス名ではなく属性セレクタを活用しましょう。これが最も宣言的でミスが少ない書き方です。

    / 属性セレクタをCSSのフックにする /
    [role=”option”][aria-selected=”true”] {
    background-color: #007bff;
    color: #ffffff;
    font-weight: bold;
    }

    / 状態が切り替わった時の微細なアニメーションも属性で制御 /
    [role=”option”] {
    transition: background-color 0.2s ease;
    }

    このように実装すれば、CSSとJavaScriptの結合度を最小限に保てます。「JavaScriptでクラスをつけ外しする」という泥臭いDOM操作から卒業し、「データ(属性)を更新すれば見た目は自動的に追従する」というアーキテクチャに切り替えるのが、中級から上級へステップアップするための秘訣です。

    —

    最後に:完璧なUIを目指すあなたへ

    `aria-selected` は単なる「装飾」ではありません。ブラウザというOSに対する、開発者からの「この要素はこういう役割で、今こうなっている」という意思表示です。

    複雑なフレームワーク(ReactやVueなど)を使っていても、結局ブラウザが解釈するのはこういった標準的な属性です。フレームワークの抽象化レイヤーの裏側で、ブラウザが何をどう処理しているのか。その視点を持ち続けるだけで、デバッグの質とスピードは劇的に変わります。

    ぜひ、次回のリスト実装では、`aria-selected` を使ったアクセシブルな設計に挑戦してみてください。あなたの書くコードが、あらゆるユーザーにとってより使いやすいものになることを願っています。

コメント

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