WAI-ARIAに対応したタブを作ってみた(作成方法)【ES6】

最近業務でタブを久々に実装することがあったのでWAI-ARIAに対応ものを作成してみました。

この記事ではその作成したタブをご紹介します。

目次

WAI-ARIAに対応したタブを作ってみた【ES6】

実装するのも

  • WAI-ARIAに対応
  • 複数タブの設置に対応

デモ

以下、ソースコードの紹介になります。

HTML

<ul class="js-tab-list tab-list" role="tab-list">
  <li class="tab-list__item">
    <button class="js-tab-button tab-button" type="button" role="tab" aria-controls="tab-panel-1" aria-selected="true">
      タブ1
    </button>
  </li>
  <li class="tab-list__item">
    <button class="js-tab-button tab-button" type="button" role="tab" aria-controls="tab-panel-2" aria-selected="false">
      タブ2
    </button>
  </li>
  <li class="tab-list__item">
    <button class="js-tab-button tab-button" type="button" role="tab" aria-controls="tab-panel-3" aria-selected="false">
      タブ3
    </button>
  </li>
</ul><!-- tab-list -->

<div class="js-tab-panel-wrapper tab-content">
  <div id="tab-panel-1" class="js-tab-panel tab-panel" role="tab-panel" aria-hidden="false">
    <p>タブ1の内容が入ります。</p>
  </div>
  <div id="tab-panel-2" class="js-tab-panel tab-panel" role="tab-panel" aria-hidden="true">
    <p>タブ2の内容が表示されます。</p>
  </div>
  <div id="tab-panel-3" class="js-tab-panel tab-panel" role="tab-panel" aria-hidden="true">
    <p>タブ3の内容です。</p>
  </div>
</div>

role属性とaria属性を使用します。

タブのボタンエリアを.tab-list

タブの内容を表示するエリアを.tab-content

.tab-listにタブのリストと分かるようにrole="tab-list"

タブのボタンにはタブ本体と分かるようにrole="tab"

タブとタブ内容を紐付けるためにaria-controls="tab-panel-1"とタブ内容のidを指定

タブが選択状態にあるかを示すためにaria-selected="true"未選択ならaria-selected="false"

タブ内容にはrole="tab-panel"

そのタブ内容が表示状態にあるかを示すためにaria-hidden="false"非表示ならaria-hidden="true"

CSS(SCSS)

//タブ ボタン
.tab-list {
  display: flex;
}

.tab-list__item {
  flex: 1;
  &:not(:first-child) {
    margin-left: 5px;
  }
}

.tab-button {
  width: 100%;
  height: 100%;
  padding: 10px;
  background: #eee;
  cursor: pointer;
  &[aria-selected="true"] {
    background: #3ac8ff;
  }
}
//===============タブ ボタン

//タブ パネル
.tab-content {
  margin-top: 20px;
}

.tab-panel {
  padding: 20px 15px;
  border: 1px solid #eee;
  &[aria-hidden="true"] {
    display: none;
  }
}
//===============タブ パネル

スタイルはサンプル用ですがポイントは以下です

aria-selected属性とaria-hidden属性で表示・非表示状態のスタイルを切り替えます。

JavaScript

class Tab {
  constructor() {
    this.tab_button = document.querySelectorAll('.js-tab-button');
  }

  init() {
    this.attachEvent();
  }

  attachEvent() {
    for(const button of this.tab_button) {
      button.addEventListener('click', (e) => {
        let id = button.getAttribute('aria-controls');
        this.hideContents(id, e);
        this.showContent(id, e);
      });
    }
  }

  hideContents(id, e) {
    //クリックしたタブ、パネルの親を取得
    let button_parent = e.target.closest('.js-tab-list');
    let panel_parent = document.querySelector(`#${id}`).closest('.js-tab-panel-wrapper');

    //表示状態のボタン、パネルの状態を取得
    let active_button = button_parent.querySelector('.js-tab-button[aria-selected="true"]');
    let active_panel = panel_parent.querySelector('.js-tab-panel[aria-hidden="false"]');

    //タブボタン
    active_button.setAttribute('aria-selected', 'false');
    //タブパネル
    active_panel.setAttribute('aria-hidden', 'true');
  }

  showContent(id, e) {
    //タブボタン
    e.target.closest('.js-tab-button').setAttribute('aria-selected', 'true');
    //タブパネル
    document.querySelector(`#${id}`).setAttribute('aria-hidden', 'false');
  }

}

const tab = new Tab();
tab.init();

class構文で記述しています。

少々長いですが、ポイントは以下となります。

  • タブボタンにクリックイベントを付与
  • 複数タブの設置に対応するために親要素を取得
  • 表示している要素を非表示にしてから別のタブを表示

タブボタンをクリックすることで各要素のaria-selectedaria-hiddenの値を切り替えます。

表示・非表示の処理は先程ご紹介したCSSで行っています。

クリックイベントを付与

for-of文でタブボタン(class.js-tab-button)にクリックイベントを付与します。

タブをクリックしたときにaria-controlsの値を取得
※タブボタンとタブ内容を紐付けるIDです

タブの切り替え処理

非表示

複数タブの設置に対応するためにclosestメソッドで親要素を取得して表示状態のタブを非表示にします。

表示

タブをクリックしたときに取得したID(aria-controlsの値)をもとに表示処理を行います。

注意点

親要素を取得するために使用しているclosestメソッドはIEでは動きません

ですが、対応するためのポリフィルがありますので以下をご確認ください。

最後に

これでWAI-ARIAに対応したタブを実装できました。
class属性だけでも実装は可能(そちら方が楽)ですが、アクセシビリティーの観点からこの方法で実装するのが良いと思います。

タブに限らずアコーディオンやハンバーガーメニューにも面倒かもしれませんがWAI-ARIAに対応したほうがいいのかなと思いました。

参考にさせて頂いた記事

https://ics.media/entry/17107/

https://to-memo.com/web/wai-aria_tab/