【ES6】タブ切り替えをWAI-ARIAに対応させる

今回は前回作成したタブ切り替えメニューをWAI-ARIAに対応させていきます。

実際のコード


See the Pen
WAI-ARIA対応タブメニュー
by naomi homma (@naomi-homma)
on CodePen.

HTMLの実装:role属性とaria属性の追加

<div class="tab">
 <ul class="tab__list" role="tab-list">
  <li class="tab__item">
   <button class="tab__button" type="button" role="tab" aria-controls="tab-panel-1" aria-selected="true">tab01</button>
  </li>
  <li class="tab__item">
   <button class="tab__button" type="button" role="tab" aria-controls="tab-panel-2" aria-selected="false">tab02</button>
  </li>
  <li class="tab__item">
   <button class="tab__button" type="button" role="tab" aria-controls="tab-panel-3" aria-selected="false">tab03</button>
  </li>
 </ul>
<div class="tab__content">
 <div class="tab__content-item" id="tab-panel-1" role="tab-panel" aria-hidden="false">
  <p class="tab__content-text">tab01の本文です。</p>
 </div>
 <div class="tab__content-item" id="tab-panel-2" role="tab-panel" aria-hidden="true">
  <p class="tab__content-text">tab02の本文ですよ!!tab02の本文ですよ!!</p>
 </div>
 <div class="tab__content-item" id="tab-panel-3" role="tab-panel" aria-hidden="true">
  <p class="tab__content-text">tab03の本文ですか??</p>
 </div>
</div>

role属性とは?

role属性は、コンテンツの役割を明示します。
今回は、どの要素がタブエリア・タブ・パネルに該当するかを明示するため以下を記述しました。

  • ul要素へrole="tab-list"
  • タブ部分となるbutton要素にrole="tab"
  • パネル部分のdiv要素にrole="tab-panel"

aria属性とは?

aria属性は、要素に状態や性質を明示させます。
今回は、タブとパネルの紐付け、タブの選択状態、パネルの表示・非表示状態を明示するため以下を記述しました。

  • タブとパネルの関連性を示すためタブへaria-controls属性を、パネルへid属性を指定
  • タブの選択状態を示すために、aria-selectedを真偽値で指定
  • パネル部分の表示・非表示の状態を伝えるためにaria-hidden属性を真偽値で指定

CSSの実装

.tab__button {
  display: block;
  font-size: 25px;
  padding: 0.5rem 1rem;
  cursor: pointer;
  border-bottom: 3px solid blue;
  opacity: 0.3;

  &[aria-selected='true'] {
    opacity: 1;
  }
}

.tab__content-item {
  display: block;

  &[aria-hidden='true'] {
    display: none;
  }
}

class 属性を使わず、aria-* 属性をセレクターとして指定しています。

JavaScriptの実装

/* -----------------------------------------
*   Script for 01
----------------------------------------- */
document.addEventListener('DOMContentLoaded', () => {
  function tabClick(e) {
    //クリックされたtabの親要素を取得
    const tabList = e.currentTarget.closest('.tab__list')
    //クリックされたtabのaria-controlsの値を取得
    const id = e.target.getAttribute('aria-controls')
    //クリックされたtabと同じ親要素を持つパネルを取得
    const contentList = document
      .querySelector(`#${id}`)
      .closest('.tab__content')

    //表示状態のボタン、パネルを取得
    const active_tabItems = tabList.querySelector('[aria-selected="true"]')
    const active_tabContentItems = contentList.querySelector(
      '[aria-hidden="false"]'
    )

    //タブボタンを非アクティブ
    active_tabItems.setAttribute('aria-selected', 'false')
    //タブパネルを非表示
    active_tabContentItems.setAttribute('aria-hidden', 'true')

    //選択されたtabを表示
    e.target.setAttribute('aria-selected', 'true')

    //選択されたtabに紐づくpanelを表示
    document.querySelector(`#${id}`).setAttribute('aria-hidden', 'false')
  }
  //全てのtabにイベントリスナー設定
  const tabs = document.querySelectorAll('.tab__item')
  tabs.forEach((tab) => {
    tab.addEventListener('click', tabClick)
  })
})

今回は以上になります!


↓↓私の師匠、もりけんさんの武骨日記。問題集、要チェック

kenjimorita.jp