Front-end Machine Coding Series #3: Build an Expandable Accordion UI with Vanilla JS

Nitin SainiNitin Saini
4 min read

In modern web interfaces, accordions help manage large amounts of content in a compact and organized format. Whether you’re displaying FAQs, product details, or expandable sections, the accordion pattern ensures only relevant information is shown, reducing visual noise.

While component libraries like Bootstrap or Material UI make this simple, building an accordion from scratch using Vanilla JavaScript strengthens your understanding of DOM manipulation, dynamic rendering, and event handling.

In this blog, we'll walk through creating an accordion UI with:

  • Multiple expandable/collapsible sections

  • One section active at a time

  • Support for a default expanded section

  • Scalable structure for adding more items dynamically

Problem Statement

Design and implement an accordion component using HTML, CSS, and JavaScript — without any frameworks.

Requirements:

  • Create at least three accordion sections

  • Each section must be expandable/collapsible on click

  • Only one section should be open at a time

  • Visually distinguish the active section

  • Keep code modular, clean, and readable

Solution:

HTML code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accordian</title>
    <link href="./index.css" rel="stylesheet" />
  </head>
  <body>
    <h1>Accordion</h1>
    <div class="accordion" id="accordion-container"></div>
    <script src="./accordion.js"></script>
  </body>
</html>

CSS Code:

body {
  font-family: Arial, sans-serif;
  background-color: #f5f5f5;
  margin: 2rem;
}

.accordion-container {
  max-width: 600px;
  margin: auto;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.1);
}

.accordion-section {
  border-bottom: 1px solid #ddd;
}

.accordion-header {
  padding: 16px;
  cursor: pointer;
  font-weight: bold;
  background-color: #eee;
  transition: background-color 0.3s ease;
}

.accordion-section.active .accordion-header {
  background-color: #4285f4;
  color: white;
}

.accordion-content {
  padding: 16px;
  display: none;
  background-color: #fafafa;
}

JavaScript Code:

const accordionData = [
  {
    id: "ac_1",
    title: "Did You Know? About the Sun",
    content:
      "The Sun accounts for 99.86% of the mass in our solar system. It’s so large that about 1.3 million Earths could fit inside it!",
  },
  {
    id: "ac_2",
    title: "Fact: Octopus Intelligence",
    content:
      "Octopuses have nine brains, blue blood, and can taste with their arms. They’re considered one of the smartest invertebrates on Earth.",
  },
  {
    id: "ac_3",
    title: "History: The Great Wall of China",
    content:
      "The Great Wall of China is over 13,000 miles long and took more than 2,000 years to complete. Contrary to popular belief, it’s not visible from space with the naked eye.",
  },
  {
    id: "ac_4",
    title: "Space: Saturn’s Rings",
    content:
      "Saturn’s rings are made mostly of ice particles and range in size from tiny grains to objects as large as a mountain.",
  },
  {
    id: "ac_5",
    title: "Tech: First Website Ever",
    content:
      "The first website ever was created by Tim Berners-Lee in 1991. It’s still live today: http://info.cern.ch/",
  },
];

document.addEventListener("DOMContentLoaded", () => {
  const accordionContainer = document.querySelector("#accordion-container");

  accordionData?.forEach((item, index) => {
    //create a section that will contain header and content
    const section = document.createElement("div");
    section.classList.add("accordion-section");

    //create a accordion header
    const sectionHeader = document.createElement("div");
    sectionHeader.classList.add("accordion-header");
    sectionHeader.textContent = item?.title;

    //create a accordion content
    const sectionContent = document.createElement("div");
    sectionContent.classList.add("accordion-content");
    sectionContent.innerHTML = `<div>${item?.content}</div>`;

    //add header and content child to section
    section.appendChild(sectionHeader);
    section.appendChild(sectionContent);

    accordionContainer.appendChild(section);

    //keep the first index open by default
    if (index === 0) {
      section.classList.add("active");
      sectionContent.style.display = "block";
    }
  });

  //handling opening and closing of accordion
  accordionContainer.addEventListener("click", (e) => {
    //find the clicked header
    const header = e.target.closest(".accordion-header");
    if (!header) {
      return;
    }
    //get the full access of parent node or div of header
    const section = header.parentNode;

    //get the content of it
    const content = section.querySelector(".accordion-content");
    //check if it has acive class or not
    const isActive = section.classList.contains("active");

    //after clicking on a accordion, remove all the classes
    document.querySelectorAll(".accordion-section").forEach((sec) => {
      sec.classList.remove("active");
      sec.querySelector(".accordion-content").style.display = "none";
    });

    if (!isActive) {
      section.classList.add("active");
      content.style.display = "block";
    }
  });
});

Wrap-Up

Building an accordion manually is a solid exercise in JavaScript fundamentals:

  • You learn to structure UI data dynamically

  • Use event delegation for performance and simplicity

  • Make your component easily extensible (just add data)

While frameworks abstract much of this, knowing how to create interactive elements like this from scratch gives you confidence and flexibility in front-end development.

Happy coding! If you have any questions or suggestions you'd like to explore further, feel free to drop a comment below.

See you in the next blog. Please don’t forget to follow me:

Twitter
LinkedIn

0
Subscribe to my newsletter

Read articles from Nitin Saini directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nitin Saini
Nitin Saini

A Full Stack Web Developer, possessing a strong command of React.js, Node.js, Express.js, MongoDB, and AWS, alongside Next.js, Redux, and modern JavaScript (ES6+)