👊

【JavaScript】タブ切り替え徹底解説

に公開


JavaScript でタブ切り替えを作る時コピペで作りがちなので、勉強を兼ねて詳しい解説を書きました。

こんな方におすすめです。

  • タブ切り替えはコピペで済ませがち
  • class のつけ外し操作がふんわりしかわかっていない
  • 使いやすいタブの元コードが欲しい

コード

結論のコードです。

<div class="tabs">
  <ul class="tab-list">
    <li class="tab-item active" tabindex="0">タブ1</li>
    <li class="tab-item" tabindex="0">タブ2</li>
    <li class="tab-item" tabindex="0">タブ3</li>
  </ul>
  <div class="tab-content">
    <div class="tab-panel active">
      <h2>タブ1の内容</h2>
      <p>ここはタブ1の内容が入ります</p>
    </div>
    <div class="tab-panel">
      <h2>タブ2の内容</h2>
      <p>ここはタブ2の内容が入ります</p>
    </div>
    <div class="tab-panel">
      <h2>タブ3の内容</h2>
      <p>ここはタブ3の内容が入ります</p>
    </div>
  </div>
</div>
.tabs {
  max-width: 500px;
  margin: 10% auto;
}

.tab-list {
  display: flex;
}

.tab-item {
  border-radius: 5px 5px 0 0;
  background-color: #fff;
  border: solid 1px skyblue;
  padding: 0.5em 1.2em;
  cursor: pointer;
}

.tab-content {
  background-color: #f5f5f5;
}

.tab-panel {
  display: none;
}

.tab-item.active {
  background-color: skyblue;
  color: #fff;
  font-weight: bold;
}

.tab-panel.active {
  display: block;
  padding: 3%;
}
.tab-panel.active h2 {
  font-size: 20px;
  font-weight: bold;
}
// タブの見出し(tab-item)を取得
const tabItems = document.querySelectorAll(".tab-item");

tabItems.forEach((tabItem) => {
  tabItem.addEventListener("click", () => {
    // すべてのタブを非アクティブにする
    tabItems.forEach((t) => {
      t.classList.remove("active");
    });
    // すべてのコンテンツを非表示にする
    const tabPanels = document.querySelectorAll(".tab-panel");
    tabPanels.forEach((tabPanel) => {
      tabPanel.classList.remove("active");
    });

    // クリックされたタブをアクティブにする
    tabItem.classList.add("active");

    // 対応するコンテンツを表示
    const tabIndex = Array.from(tabItems).indexOf(tabItem);
    tabPanels[tabIndex].classList.add("active");
  });
});

コードの解説

HTML と CSS の説明は薄めです。

HTML

最初から表示させておきたい要素(タブ 1 の見出しとタブ 1 の中身)にactiveクラスをつけておきます。

<!-- 省略 -->
<ul class="tab-list">
  <li class="tab-item active" tabindex="0">タブ1</li>
  <li class="tab-item" tabindex="0">タブ2</li>
  <li class="tab-item" tabindex="0">タブ3</li>
</ul>
<div class="tab-content">
  <div class="tab-panel active"></div>
</div>
<!-- 省略 -->

CSS

開いているタブの見出し(active)をわかりやすくするために、背景色を水色にしています。

.tab-item.active {
  background-color: skyblue;
  color: #fff;
  font-weight: bold;
}

開いていないタブの中身は見せたくないので、display:none;で非表示にしておきます。
見せたいタブの中身に対してactiveをつけているので、いまのところタブ 1 の中身だけが見えています。

.tab-panel {
  display: none;
}

見せたいタブにactiveがついているので、このときはdisplay: none;を解除したいです。
display: block;で要素が見えるようにします。

.tab-panel.active {
  display: block;
  padding: 3%;
}

JS

JS でどのようにタブを操作しているのか、詳しく解説します。

操作に必要な要素を指定する

タブの見出しをconstで定義します。

const tabItems = document.querySelectorAll(".tab-item");

タブたちをまとめてtabItemsとします、そのうちのひとつがtabItemとなり、これにaddEventListenerをします。

addEventListenerで操作したいのは、タブの見出し(tab-item)とタブの中身(tab-panel)です。
先ほどはtabItemsのうちひとつのものをtabItemとしました。同じ名前は使えないので、ここではタブの見出し単体のことをtとしましょう。

3つあるタブ(tabPanels)の中身のうちひとつを、tabPanelとします。
クリックされたものがtabPanelになるので、タブ2の中身やタブ3の中身がtabPanelになるシーンもあります。

クリックされたら

addEventListenerは「クリックされたら」の動きを含んでいます。もし見出しのどれかがクリックされたら、classList.removeで見出し・中身からactiveを削除します。

直後に見出しと中身に対してclassList.add("active");をすることで、クリックされた要素だけにactiveクラスが追加される(不要なactiveクラスが削除される)仕組みです。

中身を表示させるために、tabItemsの個数(配列)を取得します。
tabIndexは、tabItemtabItemsの中でいくつめなのかを調べています。
tabIndexが0ならひとつめの要素(タブ1)、tabIndexが1ならふたつめの要素(タブ2)にactiveクラスを追加して、と命令しています。

このスクショは、見出しを1から順番に押してconsole.logで何個目なのかをわかりやすく表したものです。

console.log(`${tabIndex}個め`);

まとめ

JavaScriptで要素を操作する時のコツは以下の通りです。

  • 操作したい要素をまず定義(const、letなど)
  • もし○○したら…はaddEventListenerで表せる
  • 複数ある要素のうち、ひとつがクリックされたら何かしたいときは、forEachが便利
    • 複数ある要素の命名時は末尾にsをつけて、クリックされたひとつの要素と名前を別にすることでわかりやすさUP
  • 配列の操作(Array)にはインデックス(添え字)の活用が便利。
  • 何を操作しているのかわからない、要素が取得できたか不安な時はとにかくconsole.log

Discussion