この記事では、タブを切り替えることで、表示されるカルーセル(Swiper)も一緒に切り替わるUIの作成について解説しています。
HTMLでタブとカルーセルの入れ物を作り、JavaScriptでタブの切り替えとSwiperの初期化を行います。そして、CSSで見た目を整えます。
Swiperというライブラリを、CDNから読み込んで使います。
目次
classList.add() ・ classList.remove()
JavaScriptのclassListは、要素が持つclass属性を操作するためのプロパティです。要素.classList.add('クラス名')でクラスを追加し、要素.classList.remove('クラス名')で取り除くことができます。
例えば、あるボタンをクリックしたときに、そのボタンだけに「選択中」を表す見た目を付けたい場合、以下のように使用します:
const btn = document.querySelector('.myButton');
btn.classList.add('is-active');
// → <button class="myButton is-active">になる
btn.classList.remove('is-active');
// → <button class="myButton">に戻る
今回のタブ切り替えでは、このadd()とremove()を組み合わせて、「クリックされたタブ・パネルだけにis-activeを付け、それ以外からは外す」という処理を行っています。
似たようなことができるclassList.toggle()というメソッドもありますが、今回は「他のタブを必ず非アクティブにする」処理なので、add/removeを分けて書いています。
タブ切り替え×カルーセルのサンプル
それでは、早速サンプルです。
タブをクリックすると、表示されるカルーセルが切り替わります。カルーセル自体も、左右にスワイプ(またはドラッグ)して動かせます。
タブを切り替えると、カルーセルの中身も一緒に切り替わります。切り替えた直後にカルーセルのコマ数がズレないよう、裏側でswiper.update()を呼んでいます。
実装の手順と方法
コードの詳細の前に、実装の手順と方法について解説していきます。
まずは、タブのボタンと、タブごとのカルーセルを入れる箱をHTMLで用意します。
カルーセル自体は、Swiperが要求する.swiper → .swiper-wrapper → .swiper-slideという決まった入れ子構造にしておきます。
<div class="jsSample-tabCarousel">
<div class="tab-carousel-tabs">
<button class="tab-carousel-tabBtn is-active" data-tab="tab1">おすすめ</button>
<button class="tab-carousel-tabBtn" data-tab="tab2">新着</button>
<button class="tab-carousel-tabBtn" data-tab="tab3">セール</button>
</div>
<div class="tab-carousel-panel is-active" id="tab1">
<div class="swiper tabSwiper1">
<div class="swiper-wrapper">
<div class="swiper-slide">おすすめ 1</div>
<div class="swiper-slide">おすすめ 2</div>
<div class="swiper-slide">おすすめ 3</div>
<div class="swiper-slide">おすすめ 4</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="tab-carousel-panel" id="tab2">
<div class="swiper tabSwiper2">
<div class="swiper-wrapper">
<div class="swiper-slide">新着 1</div>
<div class="swiper-slide">新着 2</div>
<div class="swiper-slide">新着 3</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="tab-carousel-panel" id="tab3">
<div class="swiper tabSwiper3">
<div class="swiper-wrapper">
<div class="swiper-slide">セール 1</div>
<div class="swiper-slide">セール 2</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
SwiperはCDNから読み込みます。<link>でCSSを、<script>でJS本体を読み込んでおきましょう。
あわせて、タブとパネルの見た目を整えるCSSも記述します。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
<style>
.jsSample-tabCarousel { margin-top: 20px; }
.tab-carousel-tabs { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.tab-carousel-tabBtn { padding: 10px 20px; border: none; border-radius: 6px; background: #eee; cursor: pointer; font-weight: 600; transition: 0.2s; }
.tab-carousel-tabBtn.is-active { background: #5ba9f7; color: #fff; }
.tab-carousel-panel { display: none; }
.tab-carousel-panel.is-active { display: block; }
.jsSample-tabCarousel .swiper-slide { background: #f5f5f5; border-radius: 8px; padding: 40px 0; text-align: center; font-weight: 600; font-size: 1.1rem; }
.jsSample-tabCarousel .swiper { padding-bottom: 30px; }
</style>
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
最後に、タブをクリックしたときの切り替え処理と、Swiperの初期化処理を書きます。
document.addEventListener('DOMContentLoaded', function () {
// 3つのカルーセルに共通するオプション
const swiperOptions = {
slidesPerView: 2,
spaceBetween: 16,
pagination: { clickable: true },
};
// タブごとにSwiperインスタンスを作成し、対応付けておく
const swiperMap = {
tab1: new Swiper('.tabSwiper1', swiperOptions),
tab2: new Swiper('.tabSwiper2', swiperOptions),
tab3: new Swiper('.tabSwiper3', swiperOptions),
};
const tabButtons = document.querySelectorAll('.tab-carousel-tabBtn');
const panels = document.querySelectorAll('.tab-carousel-panel');
tabButtons.forEach((btn) => {
btn.addEventListener('click', () => {
const target = btn.dataset.tab;
// 一旦すべてのタブ・パネルからis-activeを外す
tabButtons.forEach((b) => b.classList.remove('is-active'));
panels.forEach((p) => p.classList.remove('is-active'));
// クリックされたタブと対応するパネルにis-activeを付ける
btn.classList.add('is-active');
document.getElementById(target).classList.add('is-active');
// 非表示の間にサイズがずれていることがあるのでupdateしておく
if (swiperMap[target]) swiperMap[target].update();
});
});
});
ざっくりとしたコードの解説
コードは、HTML・CSS・JavaScriptの3種類です。ざっくりですが、順に解説していきます。
HTML
タブのボタン(.tab-carousel-tabBtn)には、data-tab属性で対応するパネルのIDを持たせています。
パネル側(.tab-carousel-panel)は、その中にそれぞれ独立したSwiperの構造(.swiper / .swiper-wrapper / .swiper-slide)を持たせている形です。
<div class="jsSample-tabCarousel">
<div class="tab-carousel-tabs">
<button class="tab-carousel-tabBtn is-active" data-tab="tab1">おすすめ</button>
<button class="tab-carousel-tabBtn" data-tab="tab2">新着</button>
<button class="tab-carousel-tabBtn" data-tab="tab3">セール</button>
</div>
<div class="tab-carousel-panel is-active" id="tab1">
<div class="swiper tabSwiper1">
<div class="swiper-wrapper">
<div class="swiper-slide">おすすめ 1</div>
<div class="swiper-slide">おすすめ 2</div>
<div class="swiper-slide">おすすめ 3</div>
<div class="swiper-slide">おすすめ 4</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="tab-carousel-panel" id="tab2">
<div class="swiper tabSwiper2">
<div class="swiper-wrapper">
<div class="swiper-slide">新着 1</div>
<div class="swiper-slide">新着 2</div>
<div class="swiper-slide">新着 3</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="tab-carousel-panel" id="tab3">
<div class="swiper tabSwiper3">
<div class="swiper-wrapper">
<div class="swiper-slide">セール 1</div>
<div class="swiper-slide">セール 2</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
CSS・Swiperの読み込み
CDNから読み込んだSwiperの基本スタイルに、タブの見た目や、非表示のパネルを隠すためのスタイルを追加しています。
.jsSample-tabCarousel { margin-top: 20px; }
.tab-carousel-tabs { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.tab-carousel-tabBtn { padding: 10px 20px; border: none; border-radius: 6px; background: #eee; cursor: pointer; font-weight: 600; transition: 0.2s; }
.tab-carousel-tabBtn.is-active { background: #5ba9f7; color: #fff; }
.tab-carousel-panel { display: none; }
.tab-carousel-panel.is-active { display: block; }
.jsSample-tabCarousel .swiper-slide { background: #f5f5f5; border-radius: 8px; padding: 40px 0; text-align: center; font-weight: 600; font-size: 1.1rem; }
.jsSample-tabCarousel .swiper { padding-bottom: 30px; }
JavaScript
data-tab属性は、JavaScript側では要素.dataset.tabという形で取得できます。クリックされたボタンのdataset.tabを見て、対応するIDのパネルだけを表示する、という流れです。
また、あらかじめ3つ分のSwiperインスタンスをすべて作成しておき、swiperMapというオブジェクトにまとめておくことで、タブ切り替え時にどのSwiperをupdate()すればいいかを、すぐに参照できるようにしています。
document.addEventListener('DOMContentLoaded', function () {
// 3つのカルーセルに共通するオプション
const swiperOptions = {
slidesPerView: 2,
spaceBetween: 16,
pagination: { clickable: true },
};
// タブごとにSwiperインスタンスを作成し、対応付けておく
const swiperMap = {
tab1: new Swiper('.tabSwiper1', swiperOptions),
tab2: new Swiper('.tabSwiper2', swiperOptions),
tab3: new Swiper('.tabSwiper3', swiperOptions),
};
const tabButtons = document.querySelectorAll('.tab-carousel-tabBtn');
const panels = document.querySelectorAll('.tab-carousel-panel');
tabButtons.forEach((btn) => {
btn.addEventListener('click', () => {
const target = btn.dataset.tab;
// 一旦すべてのタブ・パネルからis-activeを外す
tabButtons.forEach((b) => b.classList.remove('is-active'));
panels.forEach((p) => p.classList.remove('is-active'));
// クリックされたタブと対応するパネルにis-activeを付ける
btn.classList.add('is-active');
document.getElementById(target).classList.add('is-active');
// 非表示の間にサイズがずれていることがあるのでupdateしておく
if (swiperMap[target]) swiperMap[target].update();
});
});
});
各コードの詳細はコメントアウトにも記載しているので、チェックしてみてください。
さいごに
今回は、タブの切り替えに連動してSwiperのカルーセルも切り替わるUIの作り方についての解説でした。
今回のサンプルでは、最初から3つ分のSwiperを作成していますが、スライド枚数や画像が多い場合は、タブが選択されたタイミングで初めてSwiperを初期化する「遅延初期化」にすると、初期表示のパフォーマンスを抑えられます。
是非あわせてチェックしてみてください。

