JavaScript - タブメニューの作り方

ウェブページに表示する内容を簡単に切り替えることができるタブメニューを作ります。JavaScript の forEach() メソッドと for...of ループの反復処理でクラスの付け外しを行う方法を学びましょう。

JavaScript - タブメニューの作り方
Photo by Choong Deng Xiang / Unsplash

タブメニューとは?

タブメニューは、関連する複数のコンテンツを重ねて表示する仕組みです。見出しとなるタブをクリックすると、画面に表示する内容を切り替えることができます。ウェブサイトなどでよく見られますよね。

今回紹介するのは、JavaScript を使ってタブメニューを作る方法です。タブを三つ用意して、クリックしたら表示内容が切り替わるようにコーディングします。

この記事を読むと分かること

  • querySelectorAll()
  • forEach()
  • for...of ループ
  • classList.remove()
  • classList.add()

サンプルプロジェクト

これから作っていくのは、下のようなタブメニューです。タブメニューは、見出しとして並んでいるタブの部分と、それに対応するコンテンツで成り立っています。

タブメニューのサンプルプロジェクト
タブメニューのサンプルプロジェクト

HTML

まずは、HTML を書きましょう。ここでは、見出しとなるタブを <h2> 要素で三つ作ります。最初に表示したい Tab 1 には、class="active" を指定しておきます。

<div class="container">

  <!--見出しとなるタブ-->
  <div class="tabMenu">
    <h2 class="tab active">Tab 1</h2> <!--最初に表示-->
    <h2 class="tab">Tab 2</h2>
    <h2 class="tab">Tab 3</h2>
  </div>

</div>

タブを三つ作ったので、画面に表示するコンテンツも三つ作りましょう。Tab 1 に対応するコンテンツにも class="active" を指定してくださいね。

<div class="container">

  <div class="tabMenu">
    <h2 class="tab active">Tab 1</h2>
    <h2 class="tab">Tab 2</h2>
    <h2 class="tab">Tab 3</h2>
  </div>

  <!--画面に表示するコンテンツ-->
  <div class="tabContent">
    <div class="content active"> <!--最初に表示-->
      <p>タブ1のコンテンツ</p>
    </div>
    <div class="content">
      <p>タブ2のコンテンツ</p>
    </div>
    <div class="content">
      <p>タブ3のコンテンツ</p>
    </div>
  </div>

</div>

以上で HTML ができました。ブラウザには以下のように表示されます。

タブ三つとコンテンツ三つがブラウザに表示される
タブ三つとコンテンツ三つがブラウザに表示される

CSS

続いて、CSS です。見出しとなるタブを横並びにしましょう。画面に表示するコンテンツは、三つとも非表示にしておきますよ。

body {
  margin: 0;
  padding: 0;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: bold;
}

.container {
  width: 500px;
  height: 250px;
  border: 5px solid lightgray;
}

.tabMenu {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 70px;
  background-color: #ED7E07; /*オレンジ色*/
}
/*タブを横に並べる*/
.tab {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}

.tabContent {
  padding: 10px 40px;
  font-size: 20px;
}
/*コンテンツは非表示*/
.content {
  display: none;
 }

ブラウザには以下のように表示されます。すべてのタブの背景色はオレンジ色で、コンテンツは何も表示されていません。

CSSで見た目を指定
CSSで見た目を指定

先ほど HTML を書いたときに、Tab 1 とそれに対応するコンテンツに class="active" を指定しておきましたね。active クラスがついている場合は、タブの色を変えてコンテンツが表示されるように、CSS を追加しましょう。

/*activeクラスの追加でタブの色を変更*/
.tab.active {
  color: #ED7E07;
  background-color: white;
}
/*activeクラスの追加でコンテンツを表示*/
.content.active {
  display: block;
}

アクティブなタブは文字がオレンジ色で背景色は白、アクティブなコンテンツは画面に表示されるようになりました。

タブメニューの最初の表示スタイル
タブメニューの最初の表示スタイル

次のセクションからは、タブメニューに動きをつけるための JavaScript を書いていきます。

JavaScript

JavaScript では、タブとコンテンツの active クラスを削除/追加して、表示を切り替えられるようにしていきます。次の手順でコードを書いていきましょう。

  1. 要素を取得する
  2. タブにイベントリスナーを設定する
  3. すべての active クラスを削除する
  4. クリックされた要素に active クラスを追加する

要素を取得する

JavaScript で操作するのは、三つのタブと三つのコンテンツです。すべてのタブとコンテンツを querySelectorAll() メソッドで取得して変数に格納しておきましょう。

//すべてのtab要素を取得し、変数tabsに格納する
const tabs = document.querySelectorAll('.tab');
//すべてのcontent要素を取得し、変数contentsに格納する
const contents = document.querySelectorAll('.content');

タブにイベントリスナーを設定する

表示を切り替えるためには、どのタブがクリックされたのか、どのタブにクリックイベントが発生したのかを知る必要があります。そのために、tab 要素それぞれにイベントリスナーを設定しますよ。

変数 tabs に格納されている tab 要素一つひとつにクリックイベントを追加するために、forEach() メソッドを使いましょう。forEach() は、括弧 () に指定した関数を各要素に対して一度ずつ実行するメソッドです。

//すべてのtab要素に関数を実行する
tabs.forEach(function() {

  /*=====================================
  タブにクリックイベントを追加、
  クリックイベントが発生したら表示を切り替える処理
  =====================================*/

});

forEach() メソッドで実行する関数には引数を指定します。これは、処理の対象となる要素を順番に受け取るための変数です。ここでは tab 要素が対象となるので、tab という名前で引数を指定します。

tabs.forEach(function(tab)) {

});

今回はもう一つ引数を指定しますよ。forEach() メソッドで実行する関数に二つ目の引数を指定すると、処理の対象となっている要素のインデックス番号を受け取ることができます。カンマ , に続けて index を追加しましょう。

tabs.forEach(function(tab,index)) {

});

tab 要素それぞれにクリックイベントを追加するコードは、以下のようになります。タブがクリックされたら、表示を切り替える toggleClass という関数が実行されるようにします。

tabs.forEach(function(tab,index) {
  
  //タブにクリックイベントを追加
  tab.addEventListener('click', toggleClass);

  /*=========================================
  タブがクリックされたときに実行する関数toggleClass
  =========================================*/

});

すべての active クラスを削除する

タブがクリックされたらタブとコンテンツの表示が切り替わるよう、関数 toggleClass を定義していきましょう。

tabs.forEach(function(tab,index) {
  tab.addEventListener('click', toggleClass);

  //タブがクリックされたときに実行する関数
  function toggleClass() {

  /*==============================
  タブとコンテンツの表示を切り替える処理
  ==============================*/

  }
});

表示を切り替えるためには、まず、一旦すべてのタブとコンテンツをアクディブではない状態にします。要素.classList.remove('active') と書くと、active クラスを削除することができます。すべての tab 要素と content 要素から active クラスを削除するために、ここでは for...of ループを使いましょう。

tabs.forEach(function(tab,index) {
  tab.addEventListener('click', toggleClass);  

  function toggleClass() {

    //すべてのタブからactiveクラスを削除する
    for(const tab of tabs){
      tab.classList.remove('active');
    }
    //すべてのコンテンツからactiveクラスを削除する
    for(const content of contents){
      content.classList.remove('active');
    }

  }
});

for...of ループについては、こちらの記事を参考にしてください。

JavaScript - for ループ (繰り返し) の基本【初心者向け】
繰り返し処理を実行するために使われる for 文の書き方や、ループの中で使われる break 文と continue 文について、プログラミング初心者の方でも分かりやすいように簡単なコードを例にして解説します。

active クラスが削除されると、タブメニューはアクティブではない状態になります。

どの要素にもactiveクラスが指定されていない状態
どの要素にもactiveクラスが指定されていない状態

クリックされた要素に active クラスを追加する

最後に、クリックされたタブとそのコンテンツだけをアクティブな状態にします。アクティブな状態にするためには、要素.classList.add('active') として active クラスを追加します。

クリックされた tab 要素とそのインデックスは、forEach() メソッドで実行する関数に指定した引数 tabindex でアクセスすることができますよ。クリックされた tab 要素に active クラスを追加するコードは、以下のようになります。

//クリックされたtab要素にactiveクラスを追加する 
tab.classList.add('active');

表示するコンテンツは、クリックされた tab 要素のインデックスで指定します。contents[index] とすることで、1番目のタブがクリックされたら1番目の content 要素に、2番目のタブがクリックされたら2番目の content 要素に active クラスが追加され、画面に表示されます。

//クリックされたtab要素と同じインデックスを持つcontent要素にactiveクラスを追加する 
contents[index].classList.add('active');

以上で、関数 toggleClass を定義できました。タブがクリックされると、タブとコンテンツの active クラスを削除/追加する処理が行われ、表示が切り替わります。

tabs.forEach(function (tab,index) {
  tab.addEventListener('click', toggleClass);

  //タブがクリックされたときに実行する関数
  function toggleClass() {
    //すべてのタブとコンテンツからactiveクラスを削除する
    for(const tab of tabs){
      tab.classList.remove('active');
    }
    for(const content of contents){
      content.classList.remove('active');
    }
    //クリックされたタブとそのコンテンツにactiveクラスを追加する 
    tab.classList.add('active');
    contents[index].classList.add('active');
  }

});

完成コード

タブ切り替えメニューのコードが完成です。

/***************************/
/* タブ切り替えメニューのコード */
/***************************/

const tabs = document.querySelectorAll('.tab');
const contents = document.querySelectorAll('.content');

tabs.forEach(function (tab,index) {
  tab.addEventListener('click', toggleClass);
  function toggleClass() {
    for(const tab of tabs){
      tab.classList.remove('active');
    }
    for(const content of contents){
      content.classList.remove('active');
    }
    tab.classList.add('active');
    contents[index].classList.add('active');
  }
});

上と同じ内容をアロー関数を使って書くと、下のようになります。function キーワードが不要になるので、スッキリしたコードになりますね。

/**************************************/
/* タブ切り替えメニューのコード アロー関数使用*/
/**************************************/

const tabs = document.querySelectorAll('.tab');
const contents = document.querySelectorAll('.content');

tabs.forEach((tab,index) => {
  tab.addEventListener('click', () => {
    for(const tab of tabs){
      tab.classList.remove('active');
    }
    for(const content of contents){
      content.classList.remove('active');
    }
    tab.classList.add('active');
    contents[index].classList.add('active');
  });
});

forEach() メソッドと for…of ループ

さて、今回は、複数の要素に同じ処理を繰り返し行うために forEach() メソッドと for...of ループを使いました。forEach() メソッドには、for...of ループと違って、対象となる要素だけでなくそのインデックスにもアクセスできるという特徴があります。今回はその違いを区別するために、forEach() メソッドと for...of ループを両方使いました。

//反復処理forEach()
tabs.forEach((tab,index) => {
  tab.addEventListener('click', () => {
    //反復処理for...of
    for(const tab of tabs){
      tab.classList.remove('active');
    }
    //反復処理for...of
    for(const content of contents){
      content.classList.remove('active');
    }
    tab.classList.add('active');
    contents[index].classList.add('active');
  });
});

for...of ループを使わずに、すべての反復処理を forEach() メソッドで書くと、下のようになりますよ。

//反復処理forEach()
tabs.forEach((tab,index) => {
  tab.addEventListener('click', () => {
    //反復処理forEach()
    tabs.forEach(tab => tab.classList.remove('active'));
    //反復処理forEach()
    contents.forEach(content => content.classList.remove('active'));
    tab.classList.add('active');
    contents[index].classList.add('active');
  });
});

See the Pen JavaScript - Tab Menu by Pyxofy (@pyxofy) on CodePen.


まとめ

今回は、JavaScript でタブ切り替えメニューを作る方法を紹介しました。

コードのポイントとなったのが、forEach() メソッドや for...of ループを使った反復処理です。見出しとなるすべてのタブにクリックイベントを追加し、タブとそれに対応するコンテンツにクラスの付け外し処理を行うことで、表示が切り替わるようにコーディングしました。

最後まで読んでいただき、ありがとうございます。この記事をシェアしてくれると嬉しいです!

こちらもチェック!LinkedInThreadsMastodon X (Twitter) @pyxofyFacebook

関連記事

JavaScript - ボタンを押して表示を切り替える方法
ボタンをクリックしてコンテンツの表示 / 非表示を切り替えたり、ウェブページの表示をダークモードにする方法を解説します。CSS に切り替えたいクラスを追加して toggle() メソッドで切り替えるだけなので簡単です。
CSS Art
Articles for creating CSS Art.
CSS Animation – Fade In and Out
Poof! Now you see it, now you don’t. Let’s learn how to make sophisticated fade effects and much more in this step-by-step article.
Scratch - Pyxofy
Scratch 3.0の使い方を、プログラミング初心者や子どもにも分かりやすく紹介しています。