Tabbed Element- JavaScript & CSS
Published: 2024-03-29 00:18:01

Tabbed element adalah salah satu customized element dalam HTML, artinya element/component ini tidak disediakan langsung oleh HTML tapi dibuat sendiri sama seperti hamburger menu yang terkenal itu. Cara membuat tabbed element sebenarnya mudah, triknya adalah menyembunyikan (hide) elemen lain sementara elemen yang aktif dalam posisi terlihat (visible). Cara ini juga sama seperti yang digunakan untuk membuat pop-up window. Sebelum menuju kesana kita akan mempelajari dulu yang namanya DOM traversal.

**DOM Traversal**
DOM traversal adalah teknik untuk berpindah dan memanipulasi elemen-elemen HTML. DOM traversal sendiri kalau dibahas bisa panjang penjelasannya, disini saya akan bahas seperlunya saja. Ketika kita mempunyai sebuah halaman HTML, maka sebenarnya struktur halaman HTML tersebut terdiri dari hirarki-hirarki yang biasa dimodelkan dalam DOM tree. Contoh sebagai berikut :

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="src/style.css">
  </head>
  <body>
    <h1 id="header1"></h1>
    <p id="par1">This is text</p>
    <p id="par2">This is also text</p>
    <div class="container">
      <span>This is span</span>
      <p id="par3">This is text inside a container</p>
    </div>
    <script src="src/script.js"></script>
  </body>
</html>
```
DOM tree dari HTML diatas adalah sebagai berikut :

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/roxztr915pl4b7cndszh.png)

Hubungan tiap element dalam DOM tree diatas adalah sebagai berikut :

1. Atas dan bawah adalah hubungan parent dan children
2. Kiri dan kanan adalah hubungan siblings

DOM traversal memungkinkan kita mengakses elemen ke arah atas, bawah maupun kiri dan kanan.

**Going downward : child**
Untuk mengakses child element (arah awah) contohnya sebagai berikut :
```javascript
// Going downwards
console.log(document.body.querySelectorAll('p'));
console.log(document.body.querySelector('p'));
console.log(document.querySelector('.container').childNodes);
console.log(document.querySelector('.container').children);
```
Hasilnya sebagai berikut :

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vp6lfo35qewfqcssbjiw.png)
Perintah `querySelectorAll()` dan `childNodes` akan menghasilkan sebuah NodeList sedangkan `children` akan menghasilkan sebuah HTMLCollection. Lalu apa bedanya ? NodeList adalah sebuah array yang mana kita bisa gunakan metode `forEach()` untuk mengekstrak elemen-elemen didalmnya, sedangkan HTMLCollection tidak bisa kita gunakan metode `forEach()` karena bukan array. Tapi kita bisa gunakan trik menggunakan spread operator untuk bisa mengakses elemen dalam HTMLCollection.

```javascript
// Mengekstrak NodeList
console.log('===========');
const p = document.querySelectorAll('p');
p.forEach(element=>{
  console.log(element)
})

// Mengekstrak HTMLCollection
console.log('===========');
const collection = document.querySelector('.container').children;
[...collection].forEach(element=>{
  console.log(element)
})
```

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8gh6evj36212k4zoy0gt.png)

**Going upwards : parent/anchestor**
Beberapa method untuk mengakses parent element sebagai berikut :

```javascript
// Going upwards
console.log('===========');
console.log(document.querySelector('#par3').parentNode);
console.log(document.querySelector('#par3').parentElement);
console.log(document.querySelector('#par3').parentElement.parentElement);
console.log(document.querySelector('#par3').closest('.container'));
```
Hasilnya sebagai berikut :

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9nf8lj3haq2zoppclw4b.png)

**Going sideways : siblings**
Di javascript hanya bisa mengakses direct siblings/elements (1 langkah ke kiri dan ke kanan), kalau ingin mengakses beberapa langkah maka bisa digunakan chaining :

```javascript
// Going sideways
console.log('===========');
console.log(document.querySelector('#par2').nextElementSibling);
console.log(document.querySelector('#par2').nextSibling);
console.log(document.querySelector('#par2').previousElementSibling);
console.log(document.querySelector('#par2').previousSibling);
console.log(document.querySelector('#par2').previousElementSibling.previousElementSibling);
console.log(document.querySelector('#par2').previousSibling.previousSibling);
```
Hasilnya sebagai berikut :

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o072j0mg6d0ei841x86u.png)

**Kembali ke laptop**
Berbekal pengetahuan mengenai DOM traversal diatas untuk membuat tabbed component maka kita siapkan kode sederhana sebagai berikut :
_index.html_

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tabbed Component</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div class="container">
      <div class="tab-component">
        <div class="tab-button">
          <button class="btn btn-1 button-active" data-tab="1">Tab 1</button>
          <button class="btn btn-2" data-tab="2">Tab 2</button>
          <button class="btn btn-3" data-tab="3">Tab 3</button>
        </div>
        <div class="tab-collection tab-content-1 tab-active">
          <h5>Main Content Tab 1</h5>
          <p>
            Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ipsum voluptas nihil autem dolor laudantium recusandae nesciunt at, totam, ad dicta quisquam nemo rerum aliquam alias quis velit!
            Temporibus, beatae fugit.
          </p>
        </div>
        <div class="tab-collection tab-content-2">
          <h5>Main Content Tab 2</h5>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Delectus aliquam totam doloribus deleniti neque ab consectetur minima cumque sapiente porro?</p>
        </div>
        <div class="tab-collection tab-content-3">
          <h5>Main Content Tab 3</h5>
          <p>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis quod nulla ex voluptatem minima assumenda culpa exercitationem hic consequuntur, dignissimos illum cum dolor praesentium,
            deleniti non. Et officiis laboriosam ad?
          </p>
        </div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>
```
_styles.css_

```css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.tab-component {
  width: 800px;
}

.tab-button {
  display: flex;
  justify-content: space-evenly;
  margin-bottom: 20px;
}

.btn {
  width: 200px;
  height: 30px;
  border-radius: 9999px;
  border: none;
  transition: all 0.2s ease-in-out;
}

.btn:hover {
  cursor: pointer;
  background-color: cadetblue;
  color: wheat;
}

.button-active {
  transform: scale(1.3);
  background-color: cadetblue;
  color: wheat;
}

.tab-collection {
  height: 250px;
  line-height: 40px;
  font-size: 30px;
  padding: 10px;
  border-radius: 3px;
  display: none;
}

.tab-active {
  display: block;
  background-color: cadetblue;
  color: wheat;
}
```
_script.js_

```javascript
'use strict';

const tabCollection = document.querySelectorAll('.tab-collection');
const btn = document.querySelectorAll('.btn');
const tabButton = document.querySelector('.tab-button');

tabButton.addEventListener('click', function (e) {
  const clicked = e.target.closest('.btn');
  console.log(clicked);
  console.log(clicked.dataset.tab); // Untuk memastikan nilai data-tab

  // Jika yang di-klik bukan button maka tidak akan menjalankan operasi apapun
  if (!clicked) return;

  // Menghilangkan class yang aktif di button dan tab
  btn.forEach((button) => button.classList.remove('button-active'));
  tabCollection.forEach((tab) => tab.classList.remove('tab-active'));

  // Mengaktifkan button
  clicked.classList.add('button-active');

  // Mengaktifkan tab content
  document.querySelector(`.tab-content-${clicked.dataset.tab}`).classList.add('tab-active');
});
```
Dan berikut adalah hasilnya :

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdx9k615ghyunpwvb61s.gif)