タブ機能の作り方【アクセシブルな実装シリーズ】

かんののプロフィール画像
エンジニアかんの

前回好評いただいた「ハンバーガーメニューの実装方法決定版」

今回はハンバーガーメニューと同様によく使用されるパーツである「タブ」の実装方法について、アクセシビリティなどに配慮した実装方法や気を付けるポイントをご紹介いたします。

タブを構成するパーツ

そもそも「タブ」とはどのパーツからどのパーツまでを指すのでしょうか。
我々はよく「タブ」と一言で呼んでしまいがちですが、その実態は以下のパーツで構成されています。

  • タブ – タブパネルを切り替えるパーツ。タブを選択することで紐づいたタブパネルが表示されます。
  • タブリスト – いくつかのタブをグループ化したもの。
  • タブパネル – コンテンツを格納するパーツ。

タブのマークアップ、当てはめるロール

ブラウザや支援技術にタブの存在を伝えるためには適切なマークアップが欠かせません。

HTMLにはタブに対応したネイティブの要素、機能が用意されていないので、WAI-ARIAのロールを用いて補完する必要があります。
WAI-ARIAでは、各タブのパーツに対応するロールが用意されていますので、これらを用いて実装を進めていきます。

タブパーツに対応するWAI-ARIAのロール

  • タブ=tab
  • タブリスト=tablist
  • タブパネル=tabpanel

各パーツの実装

タブ

タブを実装するうえで気を付けるポイントは以下です。

  • フォーカスを受け取れるa要素かbutton要素で実装する。
  • role=”tab”を指定。
  • タブとタブパネルを紐づけるaria-controls属性を付与する。
  • タブの選択状況を表すaria-selected属性を付与する。
  • 未選択のタブに直接フォーカスがあたらないようにtabindex属性を付与する。
  • タブがテキストを持たない場合はaria-labelledby属性などでアクセシブルな名前を付ける。
  • 上記属性をJSで動的に制御する。

タブをクリックしたときにタブパネルが切り替わる機能が基本となります。
キーボード操作を受け付けるために、フォーカスを受け取れる要素であるaタグかbuttonタグを使用した実装が望ましいです。

また、各タブがどのタブパネルに紐づいているのかを表すためにaria-controls属性も付与します。
あわせて、現在どのタブが選択されているのかを表すaria-selected属性、選択されていないタブに直接フォーカスがあたらないようにするためのtabindex属性も付与します。

これらの属性は、タブの選択状態に合わせてJSで動的に制御します。

また、タブにテキストを持たせられない場合は、aria-labelledby属性を用いてタブパネル内の見出しを紐づけたり、aria-label属性を使用するなど、タブにアクセシブルな名前を付けることも忘れてはなりません。

タブリスト

タブリストを実装するうえで気を付けるポイントは以下です。

  • tablistロールを指定可能な要素で実装する(筆者はdivを好んで使用します)

tablistロールが適用できるHTML要素としては、menu、ol、ul、nav、div、pといったものがあります。

タブ「リスト」なのでul要素が良いかと思えますが、ul要素のロールをデフォルトのlistからtablistに変更することにより、子要素であるli要素のロールをpresentationに上書きする手間が発生します。また、li要素のロールをタブに設定する手もありますが、フォーカスを当てるという点を考慮した場合、タブはやはりa要素かbutton要素を使用して実装した方が良いでしょう。

どちらにせよネイティブのロールを書き換えて、リストの意味をなくしてしまうのであれば、もともと特定のロールが紐づいていないdiv要素(厳密に言うと紐づいていないわけではないですが)を使って実装することが良いように思われます。

ただこのあいまいな領域についてはケースバイケースとしか言いようがないので、上にあるような知識を持ったうえで、最適な選択を考えられると良いでしょう。

タブパネル

タブパネルを実装するうえで気を付けるポイントは以下です。

  • tabpanelロールを適用する。
  • tabpanelロールを適用できるsection要素、div要素で実装する。
  • タブのaria-controls属性に対応するためにid属性を付与する。
  • タブパネルにフォーカスが当たるようにtabindex属性を指定する。
  • どの項目のパネルなのか判別可能にするため、aria-labelledby属性などでラベルを付ける。

まずどのHTML要素を使用して実装すべきかですが、tabpanelロールを適用できるsection要素かdiv要素が候補になります。厳密にはp要素も使用可能なのですが、p要素は自身の中に入れられる要素に大きな制限があり、タブパネルの仕様を考えると現実的な選択肢ではありません。
section要素を使用する際は、中身に見出し要素を持つ必要があるので、以下の判断基準で使用する要素を選んでしまって良いでしょう。

  • タブパネルの中身が独立したセクションで見出しがある→section要素
  • それ以外→div要素

また、タブの実装の際に、タブとタブパネルを紐づけるaria-controls属性を指定しました。この属性はid属性を参照するので、対応するタブのaria-conrols属性で指定した文字列をタブパネルのid属性として指定します。

また、タブを選択したあとはタブパネルの中身にフォーカスが移動することが望ましいケースが多いので、tabindex属性を指定してタブパネルにフォーカスが当たるようにします。

このタブパネルがどういった内容、項目のタブパネルなのかを明示するため、ラベルを与える必要があります。
基本的にはaria-labelledby属性で対応するタブのid属性を指定することでラベルをつけることができます。対応するラベルが存在しない場合は、タブパネル内の見出しにid属性を付与してaria-labelledby属性で参照したり、タブパネル自体にaria-label属性を付与することでラベル付けすることも可能です。

具体的な実装例

今回のご紹介した内容を踏まえた実装例をこちらに紹介します。

See the Pen タブ by raikikannobaigie (@raikikannobaigie) on CodePen.

また、WAI-ARIAのAuthoring Practices Guideに載っている実装サンプルも参考になりますので、ぜひこちらもご覧ください。

自動アクティベーションバージョン
https://www.w3.org/WAI/ARIA/apg/example-index/tabs/tabs-automatic.html

手動アクティベーションバージョン
https://www.w3.org/WAI/ARIA/apg/example-index/tabs/tabs-manual.html

参考文献

HTML解体新書 仕様から紐解く本格入門
https://www.borndigital.co.jp/book/25999.html

ARIA Authoring Practices Guide 
https://www.w3.org/WAI/ARIA/apg/

こんな記事も読まれています

【2023年】ハンバーガーメニューの作り方決定版【コピペ可能】
【2023年】ハンバーガーメニューの作り方決定版【コピペ可能】
かんののプロフィール画像
かんの
ウェブアプリ開発にTailwind CSSを導入してみた
ウェブアプリ開発にTailwind CSSを導入してみた
金 伯冠のプロフィール画像
金 伯冠
【2023年版】NotoSansCJKjpをサブセット化する
【2023年版】NotoSansCJKjpをサブセット化する
さかっちょのプロフィール画像
さかっちょ
行頭に括弧や句読点、小さい文字、記号などが来ないようにする方法(禁則処理)
行頭に括弧や句読点、小さい文字、記号などが来ないようにする方法(禁則処理)
かんののプロフィール画像
かんの
上に戻る