以下では、DOMを使って「タブ切り替えUI」をアクセシビリティ対応・拡張しやすい構成で実装する方法を解説します。サンプルは**HTML/CSS/JavaScript(素のDOM API)**のみで動き、次の要件を満たします。
-
クリックによるタブ切り替え
-
キーボード操作(左右矢印/Home/End/Enter/Space)
-
WAI-ARIAロールと属性(
role="tablist",role="tab",role="tabpanel"など) -
URLハッシュによるタブの直リンク・復元
-
イベント委任でスケールしやすい構造
1. マークアップ(HTML)
タブはボタン(または<a>)を使い、タブとパネルを1対1で結びます。aria-controls と id の対応が重要です。
ポイント:
-
初期選択タブに
aria-selected="true"とtabindex="0"を付与。他はfalseと-1。 -
非表示パネルは
hidden(CSSでは[hidden]{display:none}相当)を使用。 -
aria-controls(タブ→パネル)とaria-labelledby(パネル→タブ)で双方向に結ぶ。
2. スタイル(CSS)
視覚的な選択状態とフォーカスリングを明確にします。
3. スクリプト(JS:イベント委任+ARIA更新)
-
イベント委任で
.tablistにだけリスナーを付与。 -
タブ選択時に
-
すべてのタブの
aria-selectedをfalse、tabindexを-1に -
すべてのパネルを
hiddenに -
対象タブを
true/0、対応パネルのhiddenを外す
-
-
キーボード操作(左右/Home/End/Enter/Space)に対応。
-
URLハッシュにパネルIDを設定し、直リンク・戻る進むに追従。
4. 設計の要点
-
アクセシビリティ(A11y)
-
roleと ARIA属性で関係性を明示。支援技術がタブ群であることを理解できます。 -
ロービング tabindex(選択タブのみ
tabindex="0"、他は-1")でフォーカス移動を制御。 -
hiddenはスクリーンリーダーにも非表示として扱われるため、非表示パネルに適切。
-
-
イベント委任
-
.tablistだけにリスナーをつけることで、タブの増減に強く、DOM再構築にも対応しやすい。
-
-
状態の単一情報源
-
真の表示状態はDOM属性(
aria-selected/hidden)に持たせることで、CSS・JS・アクセシビリティが同期します。
-
-
URLハッシュ連携
-
#panel-...で直リンクや履歴操作と整合を取り、再訪時も状態復元できます。
-
-
拡張性
-
同一ページに複数の
.tabsセクションを置いても、initTabsが個別に初期化します。 -
データ属性(例:
data-active-class="is-active")を導入すれば、クラス切替ベースのデザインにも即応可能。
-
5. よくある落とし穴と対策
-
display: noneのみで隠す
→ 視覚的には良いが、スクリーンリーダー向けの状態が曖昧になりやすい。hiddenと ARIA を併用する。 -
aria-selectedだけ更新してtabindexを忘れる
→ キーボードフォーカス遷移がおかしくなる。必ずセットで更新。 -
タブとパネルの対応ミス
→aria-controlsとaria-labelledbyの ID を突合。テスト時にコンソールでチェック。 -
フォーカスリングの抑制
→ アクセシビリティ低下につながるため、:focus { outline: auto; }相当を残す。
6. 拡張例
-
アニメーション:
prefers-reduced-motionを尊重しつつ、opacityやheightのトランジションを付与。 -
非同期読み込み:タブ選択時にフェッチしてパネルへ挿入(
fetch+innerHTML/DOMParser)。 -
タブの無効化:
aria-disabled="true"を付与し、CSSで見た目とポインターイベントを制御。 -
フォーム内利用:タブ切り替えでもフォーム要素の値は維持される。送信前にバリデーション連携が可能。
7. テスト項目(チェックリスト)
-
マウスクリックで正しく切り替わるか
-
Tab/Shift+Tab でタブ間フォーカス移動、左右矢印で循環移動できるか
-
Enter/Space で選択反映されるか
-
スクリーンリーダーでタブ名と選択状態が読まれるか
-
URLに
#panel-xxxを付けて直接アクセスすると該当タブが開くか -
複数タブセットを同一ページに置いても干渉しないか
以上の構成をベースにすれば、DOMの基本APIだけで使いやすく、拡張可能で、アクセシブルなタブ切り替えUIを実装できます。必要であれば、アニメーションやデータ取得連携、コンポーネント化(Web Components/フレームワーク移植)もこの土台から容易に行えます。
ChatGPT5 生成日:2025/09/11