CSS x JS: Membuat Collapsible dan Accordion

CSS x JS: Membuat Collapsible dan Accordion

Collapsible dan Accordion adalah komponen web yang mampu menampilkan dan menyembunyikan isi konten ketika judul dari konten tersebut diklik. Komponen ini umum digunakan pada konten yang menyajikan informasi tentang pertanyaan yang paling sering ditanyakan atau Frequently Asked Questions (FAQ).

Artikel ini akan membahas pembuatan komponen tersebut dengan memanfaatkan elemen HTML <details> dan <summary>. Untuk Collapsible kita akan membuatnya menggunakan CSS saja, sementara JavaScript baru akan kita pakai ketika membuat Accordion.

Sebelum mulai, berikut saya lampirkan kode latihan jika kamu ingin sambil mempraktikkannya:

<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Membuat Collapsible dan Accordion | divClassId</title>
  <link rel="stylesheet" href="./style.css">
  <script defer src="./script.js"></script>
</head>
<body>
  <aside class="faq">
    <h3>Frequently Asked Questions</h3>
    <div class="faq__items">
      <details open>
        <summary>
          <strong>Apa itu HTML?</strong>
          <img src="./chevron.svg" alt="">
        </summary>
        <p>HTML adalah bahasa <em>markup</em> yang digunakan untuk menyusun struktur web.</p>
      </details>
      <details>
        <summary>
          <strong>Apa itu CSS?</strong>
          <img src="./chevron.svg" alt="">
        </summary>
        <p>CSS adalah bahasa <em>stylesheet</em> yang digunakan untuk mengatur tampilan atau visual web.</p>
      </details>
      <details>
        <summary>
          <strong>Apa itu JavaScript?</strong>
          <img src="./chevron.svg" alt="">
        </summary>
        <p>JavaScript adalah bahasa pemrograman yang digunakan pada web agar bisa tampil dinamis dan interaktif.</p>
      </details>
    </div>
  </aside>
</body>
</html>
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --color-black: #111111;
  --color-green: #0b6758;
  --color-white: #fcfcfc;
}

html {
  height: 100%;
}

body {
  background-color: var(--color-green);
  color: var(--color-black);
  font-family: sans-serif;
  height: 100%;
  line-height: 1.5;
}

.faq {
  padding: 20px 10px;
}

.faq > h3 {
  color: var(--color-white);
  font-size: 1.25rem;
  text-align: center;
}

.faq__items {

}

.faq__items > details {

}

.faq__items > details > summary {

}

.faq__items > details[open] > summary > img {

}

.faq__items > details > p {

}

Untuk gambar chevron.svg bisa kamu unduh pada tautan berikut:

https://github.com/mochamadboval/divclassid/blob/collapsible-accordion/collapsible-accordion/chevron.svg

Sekarang, mari kita buat!

Membuat Collapsible

Jika kamu menjalankan latihan di atas, kamu akan melihat bahwa penggunaan elemen <details> dan <summary> akan langsung menghasilkan komponen ini. Jadi, tugas kita selanjutnya adalah hanya tinggal mengatur tampilannya saja.

Tampilan elemen <details> dan <summary> yang langsung menghasilkan Collapsible

Untuk permulaan, kita beri style berikut terlebih dahulu agar elemen container FAQ memiliki background putih dan tampil di tengah (seperti judulnya):

.faq__items {
  background-color: var(--color-white);
  margin: 10px auto 0;
  max-width: 360px;
  padding: 10px;
}

.faq__items > details {
  margin-bottom: 1px;
}
  • max-width: 360px ditambahkan agar lebar container responsif dengan lebar maksimalnya sebesar 360px saja.
  • margin: 10px auto 0 ditambahkan untuk memberi jarak antara container dengan judul di atasnya sebesar 10px dan nilai auto akan membuatnya berada di tengah secara horizontal.
  • padding: 10px ditambahkan agar konten di dalam container dengan tepinya memiliki jarak sebesar 10px.
  • margin-bottom: 1px pada selector .faq__items > details ditambahkan agar ada sedikit jarak antara item atau masing-masing FAQ (efeknya akan terlihat nanti).

Style awal dari Collapsible

Selanjutnya, kita beri style berikut untuk mengatur tampilan dari setiap judul (item) FAQ:

.faq__items > details > summary {
  align-items: center;
  background-color: var(--color-green);
  color: var(--color-white);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  list-style: none;
  padding: 10px;
}
  • list-style: none ditambahkan untuk menghilangkan tanda panah bawaan elemen <summary>.
  • cursor: pointer ditambahkan agar kursor mouse berubah ketika berada di atas judul item menjadi ikon yang menandakan bahwa itu bisa diklik.
  • display: flex dan align-items: center ditambahkan untuk mengaktifkan CSS Flexbox pada elemen ini sehingga kita bisa mengatur posisi elemen-elemen di dalamnya agar ke tengah secara vertikal.
  • justify-content: space-between ditambahkan agar jarak antara judul dan tanda chevron saling berjauhan.

Tampilan judul item FAQ setelah diatur

Saat ini tampilan dari setiap judul item sudah lebih baik. Namun, masih ada satu hal lagi yang bisa kita percantik, yaitu tanda chevron yang akan menyesuaikan arahnya tergantung apakah item FAQ sedang terbuka atau tidak.

Untuk persoalan ini CSS masih dapat menanganinya dengan memanfaatkan selector details[open] dan mengubah arah chevron-nya menggunakan fungsi CSS rotateX() milik property transform, seperti berikut:

.faq__items > details[open] > summary > img {
  transform: rotateX(180deg);
}

Kini arah tanda chevron menyesuaikan dengan terbuka tidaknya item FAQ

Terakhir, kita hanya perlu mengatur jarak paragraf di dalamnya dengan style berikut:

.faq__items > details > p {
  padding: 10px;
}

Tampilan utuh dari Collapsible

Membuat Accordion

Accordion sebenarnya serupa dengan Collapsible. Bedanya, komponen ini hanya dapat menampilkan satu item FAQ saja dan akan menyembunyikan item lainnya yang sedang terbuka.

Karena serupa, sekarang kita hanya tinggal membuat efek tersebut saja dengan bantuan JavaScript. Berikut adalah kodenya:

document.addEventListener('DOMContentLoaded', () => {
  const faq = Array.from(document.querySelectorAll('.faq__items > details'));

  faq.forEach((item) => {
    item.addEventListener('click', (event) => {
      const active = faq.find((item) => item.open);

      if (!event.currentTarget.open && active) {
        active.open = false;
      }
    });
  });
});

Berikut penjelasannya:

  • document.addEventListener('DOMContentLoaded', () => {
      ...
    });
    

    Event DOMContentLoaded ditambahkan untuk memastikan kode JavaScript di dalamnya baru akan tereksekusi setelah kode HTML selesai dimuat dan tersedia pada DOM.

  • const faq = Array.from(document.querySelectorAll('.faq__items > details'));
    

    Kode ini akan mengambil semua elemen <details> dan menyimpannya ke dalam variabel faq.

    Perlu diperhatikan bahwa terjadi konversi tipe data dari yang semula berbentuk NodeList object menjadi Array. Ini penting karena nantinya kita akan menggunakan method find() yang hanya tersedia pada Array.

  • faq.forEach((item) => {
      item.addEventListener('click', (event) => {
        ...
      });
    });
    

    Kode ini akan melakukan perulangan pada variabel faq sehingga kita dapat menempatkan event click untuk setiap item (elemen) yang ditampungnya.

  • const active = faq.find((item) => item.open);
    

    Kode ini akan mencari elemen <details> yang sedang terbuka (memiliki atribut open) dan menyimpannya ke dalam variabel active.

  • if (!event.currentTarget.open && active) {
      active.open = false;
    }
    

    Kode ini akan mencocokkan variabel active yang bernilai true dengan nilai dari !event.currentTarget.open. Perlu diperhatikan bahwa tanda ! di awal kode event.currentTarget.open akan membalik nilainya dari yang semula false menjadi true.

    Dengan begitu, variabel active yang menampung elemen <details> dengan atribut open dapat kita ubah nilainya menjadi false, sehingga item FAQ lainnya yang sedang terbuka akan otomatis tertutup dan tinggal menyisakan item yang baru saja kita klik yang terbuka.

Tampilan setelah penerapan efek Accordion pada Collapsible sehingga hanya dapat membuka satu item FAQ saja


Demikian pembahasan tentang membuat Collapsible dan Accordion. Semoga bermanfaat.