CSSとJavaScriptでタブメニューを作る

素のCSSとJavaScriptで、簡単に使えるタブメニューを作りたいなと思いました。
実際、簡単になっているかはわかりません。
スタイルを自由に変更できるようにしたかったので、その観点を重視してみました。

# 環境
HTML, CSS, JavaScript
（レイアウト用にBootstrap5.0を使ってます）

# 表示結果
ヘッダーをクリックすると、ボディーの表示内容が変わるシンプルなメニューです。
![002.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641121/2505eae5-3df7-fa0a-0f4c-30f5fb0efd9e.gif)

# HTML
Bootstrapの読み込みとかは抜いてます。
ヘッダーとボディーに `data-tab-id` 属性を付け、同じ値で対応させます。

```
<body class="container-fluid h-h100 bg-light">
    <div class="row center-align" style="height: 5%;">
        <!-- タブヘッダー -->
        <div id="tab-head-parent" class="col-5 h-h100 center-align">    
            <div data-tab-id="1" class="tab-head-card h-h100 center-align" style="width: 15%;">Tab-A</div>
            
            <div class="h-h100" style="width: 2.5%;"></div>
            
            <div data-tab-id="2" class="tab-head-card disable-tab-head h-h100 center-align" style="width: 15%;">Tab-B</div>
            
            <div class="h-h100" style="width: 2.5%;"></div>
            
            <div data-tab-id="3" class="tab-head-card disable-tab-head h-h100 center-align" style="width: 15%;">Tab-C</div>
        </div>
    </div>

    <div class="row center-align" style="height: 20%;">
        <div class="col-5 h-h100">
            <!-- タブボディー -->
            <div data-tab-id="1" class="w-w100 h-h100 tab-body-card center-align">Tab-A-body</div>
                        
            <div data-tab-id="2" class="w-w100 h-h100 tab-body-card center-align" style="display: none;">Tab-B-body</div>

            <div data-tab-id="3" class="w-w100 h-h100 tab-body-card center-align" style="display: none;">Tab-C-body</div>
        </div>
    </div>
</body>


```

# CSS
上3つがタブ用で、`.w-w100` からはおまけです。

```
/* ======= タブヘッダー用 ======= */
.tab-head-card {
    border-radius: 0.75em 0.75em 0 0;
    background-color: rgba(255, 127, 0, 1);
    cursor: pointer;
    transition: .2s;
}

/* ======= 無効なタブヘッダー用 ======= */
.disable-tab-head {
    opacity: 0.5;
}

/* ======= タブ本体用 ======= */
.tab-body-card {
    border-radius: 0 0 0.75em 0.75em;
    border-top: 0.15em solid rgba(255, 127, 0, 1);
    background-color: rgba(255, 255, 255, 1);
    box-shadow: 0 0.15rem 0.4rem 0.05rem rgba(0, 0, 0, 0.1), 0 0 0.02rem rgba(0, 0, 0, 0.1);
    transition: .2s;
}

/* 幅100% */
.w-w100 {
    width: 100%;
}

/* 高さ100% */
.h-h100 {
    height: 100%;
}

/* 縦横中央揃え */
.center-align {
    display: flex;
    justify-content: center;
    align-items: center;
}

/* 縦中央、左揃え */
.vcenter-align {
    display: flex;
    align-items: center;
}
```

# JavaScript
まず、ヘッダーの親要素に対するクリックイベントを拾います。
そして、HTMLで付与した`data-tab-id`属性を使って、`target`からどれをクリックしたのかを探ります。

表示形式によっては、最後に捜査しているdisplayをblockに変えるか、変数にしてもよいですね。

```
document.getElementById('tab-head-parent').addEventListener('click', ev => {
    const el = ev.target;
    
    if (el.hasAttribute('data-tab-id')) {        
        let tabId;
        let tabEnableId = el.getAttribute('data-tab-id');
        
        // ヘッダーの表示切替
        document.querySelectorAll('.tab-head-card').forEach((tabHeadDoc) => {
            tabId = tabHeadDoc.getAttribute('data-tab-id');
            
            if (tabId === tabEnableId) {
                tabHeadDoc.classList.remove('disable-tab-head');
            } else {
                tabHeadDoc.classList.add('disable-tab-head');
            }
        });
        
        // 本体の表示切替
        document.querySelectorAll('.tab-body-card').forEach((tabBodyDoc) => {
            tabId = tabBodyDoc.getAttribute('data-tab-id');

            if (tabId === tabEnableId) {
                tabBodyDoc.style.display = 'flex';
            } else {
                tabBodyDoc.style.display = 'none';
            }
        });        
    }
});
```

# 所感？ 
タブメニューを解説している方はたくさんいらっしゃると思います。
その点からもあまり有用ではないかもしれませんが、わりとまとまったかなと思うので
ご参考になれば幸いです。