今回は、JavaScriptを使ってタブの切り替えを実装する方法について、初心者向けに解説していきます。
まずタブ切り替えの大枠を把握しよう
タブ切り替えを実装する流れは、大きく分けて3つです。
① HTMLとCSSでタブを設置
② コンテンツも設置
② JavaScriptでタブ切り替えを実装
そして、JavaScriptで実装する内容は以下に分解されます。
① タブとコンテンツをすべて取得
② クリックイベントを設定
③ すべてのタブとコンテンツの「active」クラスを外す
④ クリックしたタブに「active」クラスを付ける
⑤の対象コンテンツにも「active」クラスを付ける
つまりJavaScriptでは「クラスの付け替え」を行うことがメインの実装になります。
タブ切り替えの実装サンプル
実装のサンプルをご確認ください。
実際に操作したり、ざっとコードを確認してみましょう。
See the Pen
Untitled by shotamura29 (@shotamura29)
on CodePen.
ここからはJavaScriptでタブ切り替えを実装する方法について、ステップごとに紹介します。
順番に丁寧に理解していきましょう。
STEP1:まずタブ切り替えのボタンを設置する
まずタブ部分を設置しましょう。
サンプルのHTMLとCSSを紹介します。
HTML
<!-- タブボタン -->
<div class="tab-buttons">
<button class="tab-btn active" data-tab="jujutsu">呪術廻戦</button>
<button class="tab-btn" data-tab="oshinoko">推しの子</button>
<button class="tab-btn" data-tab="frieren">葬送のフリーレン</button>
</div>デフォルトで表示するコンテンツのタブに、「active」クラスを付与します。
このactiveクラスを付け外しを行うことで、タブ切り替えを行います。
そして、タブとコンテンツを紐づけるためにdata属性(今回はdata-tabと設定)を指定します。
CSS
.tab-buttons {
display: flex;
}
.tab-btn {
padding: 10px 16px;
border: none;
background: #eee;
cursor: pointer;
}
.tab-btn.active {
background: #333;
color: #fff;
}タブボタンをflexboxで横並びさせています。
STEP2:タブ切り替えのコンテンツを設置
次に、タブのコンテンツを設置します。
HTML
<!-- コンテンツ -->
<div class="tab-contents">
<div class="tab-content active" id="jujutsu">
<h2>呪術廻戦</h2>
<p>
呪いと戦う呪術師たちのバトルアクション作品。<br>
主人公・虎杖悠仁が「呪いの王」宿儺の力を宿しながら戦うストーリー。
</p>
<p>▶ 見どころ:迫力の戦闘シーンと個性豊かなキャラクター</p>
</div>
<div class="tab-content" id="oshinoko">
<h2>推しの子</h2>
<p>
芸能界の裏側を描く衝撃作。<br>
転生×サスペンス×アイドルという異色の組み合わせが魅力。
</p>
<p>▶ 見どころ:予想を裏切るストーリー展開</p>
</div>
<div class="tab-content" id="frieren">
<h2>葬送のフリーレン</h2>
<p>
魔王討伐後の世界を描くファンタジー。<br>
長寿のエルフ・フリーレンが人間との時間を振り返る物語。
</p>
<p>▶ 見どころ:静かで深い感情描写</p>
</div>
</div>タブボタンと同じように、デフォルトで表示させるコンテンツにはactiveクラスを付与させます。
そして、それぞれのコンテンツのidには対応するタブのdata属性の値を指定します。
CSS
.tab-content {
display: none;
padding: 20px;
border: 1px solid #ccc;
}
.tab-content.active {
display: block;
}STEP3:JavaScriptでタブ切り替えを実装
最後に、JavaScriptの実装を行います。
以下が全体のコードです。
5つのステップがあるので、順番に解説していきます。
// ① タブボタンとコンテンツを取得
const tabButtons = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
// ② クリックイベントを設定
tabButtons.forEach(button => {
button.addEventListener('click', () => {
// ③ すべてのactiveを削除
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// ④ クリックされたタブにactive追加
button.classList.add('active');
// ⑤ 対応するコンテンツを表示
const target = button.dataset.tab;
document.getElementById(target).classList.add('active');
});
});① タブボタンとコンテンツを取得
// ① タブボタンとコンテンツを取得
const tabButtons = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');まずタブボタンとコンテンツをそれぞれ取得し、変数に格納します。
これは、それぞれをJavaScriptで操作できるようにするためです。
.tab-btn→ タブのボタン(呪術廻戦・推しの子など).tab-content→ 表示されるコンテンツ
querySelectorAll()は、指定したセレクタに一致する要素をすべて取得するメソッドです。
ポイント
・複数あるので「配列のようなもの(NodeList)」で返ってくる
・後でまとめて処理できるようにしている
② クリックイベントを設定
tabButtons.forEach(button => {
button.addEventListener('click', () => {
});
});次に、各タブボタンに「クリックされたときの処理」を設定します。
forEach→ タブボタンを1つずつ取り出してaddEventListener→ イベントを登録する
というイメージです。
ポイント
・タブは複数あるので「1個ずつイベントを付ける」必要がある
・クリックされたときだけ処理が動くように実装
③ すべてのactiveを削除
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));一度、すべてのタブとコンテンツから active クラスを削除します。
この処理を行うことで、
・複数のタブが選択状態になる
・コンテンツが複数表示される
といった挙動を防ぐことができます。
ポイント
・「一旦すべてリセットしてから、選び直す」という考え方
④ クリックされたタブにactive追加
button.classList.add('active');クリックされたボタンに active クラスを付与します。
⑤ 対応するコンテンツを表示
const target = button.dataset.tab;
document.getElementById(target).classList.add('active');ここが「タブ切り替えの核心」です。
まずは data属性を取得
button.dataset.tabHTMLで書いた、data-tab=""の値を取得します。
以下のボタンであれば、jujutsuが取得されます。
<button data-tab="jujutsu">次に対応するid名を持つ要素を取得
document.getElementById(target) jujutsuが取得されていたら、対応するid名jujutsuを持つ要素を所得します。
jujutsu→<div id="jujutsu">
最後に表示
.classList.add('active')最後に、取得した要素にactiveクラスを付与することで、
クリックしたタブに対応するコンテンツを表示します。
まとめ
いかがでしたでしょうか。
単にコピペをすれば、実装自体は簡単です。
しかし、コードの意味を理解して実装することで、他の実装にも応用を効かせることができます。
またエラーなどうまく動作しないときにも、原因究明にかかる時間を削減できます。
既存コードを読み解くために助けにもなります。
「1行ずつコードの意味を理解する」ということを意識して実装を行なっていきましょう。


