HTMLページでタブのUIを実装する方法として
の3つの方法があります。今回は、HTML+CSS+JavaScriptで実装する方法を紹介します。
以下のHTMLファイルを作成します。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link href="SimpleTab.css" rel="stylesheet" />
</head>
<body>
<h1>タブのUIデモ</h1>
<div class="tabs" role="tablist" aria-label="タブ">
<button class="tab-btn" role="tab" id="t-01" aria-controls="p-01" aria-selected="true">タブ No.1</button>
<button class="tab-btn" role="tab" id="t-02" aria-controls="p-02" aria-selected="false">タブ No.2</button>
<button class="tab-btn" role="tab" id="t-03" aria-controls="p-03" aria-selected="false">タブ No.3</button>
</div>
<section class="tab-panel is-active" role="tabpanel" id="p-01" aria-labelledby="t-03">
<p>タブ No.1 のコンテンツ</p>
<p>あああ</p>
<p>いいい</p>
<p>ううう</p>
</section>
<section class="tab-panel" role="tabpanel" id="p-02" aria-labelledby="t-02">
<p>タブ No.2 のコンテンツ</p>
<p></p>>AAA</p>
<p>BBB</p>
<p>CCC</p>
</section>
<section class="tab-panel" role="tabpanel" id="p-03" aria-labelledby="t-03">
<p>タブ No.3 のコンテンツ</p>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<script>
const tabs = [...document.querySelectorAll('.tab-btn')];
const panels = new Map(tabs.map(t => [t.id, document.getElementById(t.getAttribute('aria-controls'))]));
function activate(tab) {
tabs.forEach(t => t.setAttribute('aria-selected', t === tab ? 'true' : 'false'));
panels.forEach((p, id) => p.classList.toggle('is-active', id === tab.id));
tab.focus();
}
tabs.forEach(t => t.addEventListener('click', () => activate(t)));
/*
// キーボード左右で移動(アクセシビリティ)
document.querySelector('[role="tablist"]').addEventListener('keydown', (e) => {
if (!['ArrowLeft','ArrowRight','Home','End'].includes(e.key)) return;
e.preventDefault();
const i = tabs.findIndex(t => t.getAttribute('aria-selected') === 'true');
let next = i;
if (e.key === 'ArrowRight') next = (i + 1) % tabs.length;
if (e.key === 'ArrowLeft') next = (i - 1 + tabs.length) % tabs.length;
if (e.key === 'Home') next = 0;
if (e.key === 'End') next = tabs.length - 1;
activate(tabs[next]);
});
*/
</script>
</body>
</html>
.tabs {
display: flex;
gap: 8px;
padding-left: 2px;
}
.tab-btn {
position: relative;
background: #f5f5f5;
border: 1px solid #ccc;
border-bottom: none;
padding: 10px 14px;
color: #606060;
cursor: pointer;
border-radius: 8px 8px 0 0;
margin-bottom: -1px;
transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.tab-btn:hover {
background: #fafafa;
color: #404040;
}
.tab-btn[aria-selected="true"] {
background: #ffffff;
color: #000;
border-color: #4da3ff;
z-index: 1;
}
.tab-panel {
display: none;
padding: 16px 14px;
border: 1px solid #ccc;
border-radius: 0 8px 8px 8px;
background: #ffffff;
margin-top: -1px;
}
.tab-panel.is-active {
display: block;
}
以下のコードでtab-btnクラスの全てのタブボタンを配列化します。
...はスプレッド構文で、document.querySelectorAll('.tab-btn') はNodeListで戻りますが、...により、配列リテラルに詰めなおしできます。
const tabs = [...document.querySelectorAll('.tab-btn')];
タブのボタンにタブのボタンに対応したコンテンツのパネルを関連付けます。
const panels = new Map(tabs.map(t => [t.id, document.getElementById(t.getAttribute('aria-controls'))]));
tabsの配列から、aria-controls属性を読み出します。aria-controlsには対応するパネルのIDが記述されています。
PanelのDOM要素をgetElementById()メソッドで取得します。パネルのDOM要素と、タブのIDをセットにしてMAPに挿入します。
panels["t-01"] のコードで t-01タブのパネルのDOM要素にアクセスできます。
const panels = new Map();
for (const t of tabs) {
const panelId = t.getAttribute('aria-controls');
const panelEl = document.getElementById(panelId);
panels.set(t.id, panelEl);
}
タブのボタンをクリックされるとactivate関数が呼び出されます。tabにはクリックされたタブのDOMオブジェクトが渡されます。
tabs配列をスキャンして t===tab であればaria-selected属性にtrueをセットし、そうでなければfalseをセットします。
同様にpanels変数もスキャンし、id === tab.id であれば、パネルにis-activeクラスを追加し、そうでなければis-activeクラスを外します。
toggleメソッドの第2引数は「強制フラグ」です。true ならクラスを必ず付ける、false なら必ず外す、という指定になります。
is-activeクラスがサブクラスに付与されることでパネルが画面に表示されます。
function activate(tab) {
tabs.forEach(t => t.setAttribute('aria-selected', t === tab ? 'true' : 'false'));
panels.forEach((p, id) => p.classList.toggle('is-active', id === tab.id));
tab.focus();
}
tabs配列のclickイベントにactivate(t) の呼び出しをセットします。tは配列の各要素になりますので、id="t-02"のボタンであれば、activate((t-02のDOM要素))が呼び出されます。
tabs.forEach(t => t.addEventListener('click', () => activate(t)));
上記のHTMLファイルをWebブラウザで表示します。下図のページが表示されます。[タブ No.1]が選択された状態となります。
[タブ No.2]をクリックすると、[タブ No.2]が選択され、下部のパネルの内容も変化します。
同様に[タブ No.3]をクリックした場合は下図の表示となります。
HTMLページでタブのUIを実装できました。
タブのボタンはbuttonタグで実装されているため、form内に配置した場合、submitされてしまう場合があります。その場合は、type="button" を記述します。
<div class="tabs" role="tablist" aria-label="タブ">
<button type="button" class="tab-btn" role="tab" id="t-01" aria-controls="p-01" aria-selected="true">タブ No.1</button>
<button type="button" class="tab-btn" role="tab" id="t-02" aria-controls="p-02" aria-selected="false">タブ No.2</button>
<button type="button" class="tab-btn" role="tab" id="t-03" aria-controls="p-03" aria-selected="false">タブ No.3</button>
</div>