DocsHub
JavascriptIntermediate

Accordion

Build an accordion component where clicking a section header expands or collapses its content.

Accordion

Problem

Build an accordion with multiple sections. Clicking a section header expands it to show its content and collapses any other open section. Clicking an open section's header collapses it.

Page loads
→ All sections collapsed

User clicks "What is JavaScript?"
→ That section expands, shows its content
→ Any other open section collapses

User clicks the same header again
→ Section collapses

User clicks "What is Python?"
→ "What is Python?" expands
→ "What is JavaScript?" automatically collapses

Logic

  1. Select all accordion headers
  2. Listen for click on each header using event delegation
  3. Check if the clicked section is already open
  4. Close all sections first
  5. If it was not already open — open the clicked one
  6. Use max-height with a CSS transition for smooth expand/collapse
  7. Rotate an arrow icon to indicate open/closed state

Flow

yes no User clicks a header Find the parent accordion item Is this item already open? Close all items Close all items Open the clicked item Done — all closed Done — one open

HTML Structure

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Accordion</title>
    <style>
      body {
        font-family: sans-serif;
        max-width: 520px;
        margin: 60px auto;
        padding: 0 20px;
      }

      /* each accordion section */
      .accordion-item {
        border: 1px solid #e0e0e0;
        border-radius: 8px;
        margin-bottom: 10px;
        overflow: hidden;
      }

      /* clickable header */
      .accordion-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 16px 18px;
        cursor: pointer;
        font-size: 1rem;
        font-weight: 600;
        color: #222;
        background: #fafafa;
        user-select: none;
      }

      .accordion-header:hover {
        background: #f0f0f0;
      }

      /* arrow icon — rotates when open */
      .arrow {
        font-size: 0.85rem;
        color: #888;
        transition: transform 0.25s ease;
      }

      /* rotate arrow when item is open */
      .accordion-item.open .arrow {
        transform: rotate(90deg);
      }

      /* content wrapper — collapsed by default */
      .accordion-content {
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease;
      }

      /* inner padding — separate from content wrapper
         so max-height transition is not affected by padding */
      .accordion-content-inner {
        padding: 0 18px 16px;
        font-size: 0.95rem;
        color: #555;
        line-height: 1.6;
      }
    </style>
  </head>
  <body>
    <h1>FAQ</h1>

    <!-- accordion container -->
    <div id="accordion">

      <!-- each item: header + content -->
      <div class="accordion-item">
        <div class="accordion-header">
          <span>What is JavaScript?</span>
          <span class="arrow">▶</span>
        </div>
        <div class="accordion-content">
          <div class="accordion-content-inner">
            JavaScript is a programming language that runs in browsers and
            servers. It is used to build interactive websites, web apps,
            and even backend systems with Node.js.
          </div>
        </div>
      </div>

      <div class="accordion-item">
        <div class="accordion-header">
          <span>What is Python?</span>
          <span class="arrow">▶</span>
        </div>
        <div class="accordion-content">
          <div class="accordion-content-inner">
            Python is a beginner friendly programming language known for
            its simple syntax. It is widely used in data science, automation,
            and backend development.
          </div>
        </div>
      </div>

      <div class="accordion-item">
        <div class="accordion-header">
          <span>What is MongoDB?</span>
          <span class="arrow">▶</span>
        </div>
        <div class="accordion-content">
          <div class="accordion-content-inner">
            MongoDB is a NoSQL database that stores data as flexible,
            JSON-like documents instead of tables and rows like traditional
            databases.
          </div>
        </div>
      </div>

    </div>

    <script src="script.js"></script>
  </body>
</html>

Solution

// Step 1 — select the accordion container and all items
const accordion = document.querySelector("#accordion");
const items = document.querySelectorAll(".accordion-item");

// Step 2 — use event delegation
// one listener on the container handles clicks on any header
accordion.addEventListener("click", (e) => {
  // find the header that was clicked
  const header = e.target.closest(".accordion-header");
  if (!header) return; // clicked somewhere else — ignore

  // Step 3 — find the parent accordion item
  const clickedItem = header.closest(".accordion-item");

  // Step 4 — check if this item is already open
  const isAlreadyOpen = clickedItem.classList.contains("open");

  // Step 5 — close all items first
  closeAllItems();

  // Step 6 — if it was not already open, open it now
  // this creates the toggle effect — click again to close
  if (!isAlreadyOpen) {
    openItem(clickedItem);
  }
});

// Step 7 — close all accordion items
function closeAllItems() {
  items.forEach((item) => {
    item.classList.remove("open");

    const content = item.querySelector(".accordion-content");
    // set max-height to 0 — triggers the collapse transition
    content.style.maxHeight = "0px";
  });
}

// Step 8 — open a specific accordion item
function openItem(item) {
  item.classList.add("open");

  const content = item.querySelector(".accordion-content");
  const inner = item.querySelector(".accordion-content-inner");

  // Step 9 — set max-height to the actual content height
  // scrollHeight gives the full height of the content
  // including parts that are currently hidden by overflow
  content.style.maxHeight = inner.offsetHeight + "px";
}

Code Execution

Trace through clicking "What is JavaScript?" (first time, all closed):

StepCodeResult
Find headere.target.closest(".accordion-header")JS header element
Find itemheader.closest(".accordion-item")JS accordion item
Check openitem.classList.contains("open")false
Close allcloseAllItems()all max-height = 0px
Open clickedopenItem(item)adds "open" class
Set max-heightcontent.style.maxHeight = inner.offsetHeight + "px"e.g. "96px"
ResultJS section expands, arrow rotates

Trace through clicking "What is JavaScript?" again (now open):

StepCodeResult
Check openitem.classList.contains("open")true
Close allcloseAllItems()max-height = 0px, class removed
isAlreadyOpen checktrue → skip openItem()item stays closed
ResultJS section collapses

Trace through clicking "What is Python?" while JS section is open:

StepCodeResult
Close allcloseAllItems()JS section collapses too
Check openPython item was not openfalse
Open PythonopenItem(pythonItem)Python section expands
Resultonly Python is open now

Output

Page loads               → all sections collapsed, arrows pointing right
Click "JavaScript"       → JavaScript section expands, arrow rotates down
Click "JavaScript" again → JavaScript section collapses
Click "Python"           → Python expands, JavaScript stays closed
Click "MongoDB"          → MongoDB expands, Python collapses

On this page