DocsHub
JavascriptIntermediate

Tabs Component

Build a tabs component where clicking a tab shows its corresponding content and hides the others.

Tabs Component

Problem

Build a tabs component with multiple tab buttons. Clicking a tab shows its content panel and hides all others. The active tab is highlighted.

Page loads
→ First tab "HTML" is active, its content is shown

User clicks "CSS" tab
→ "CSS" tab becomes active and highlighted
→ "CSS" content panel shows
→ "HTML" content panel hides

User clicks "JavaScript" tab
→ "JavaScript" tab becomes active
→ Only "JavaScript" content is visible

Logic

  1. Select all tab buttons and all content panels
  2. Each tab button has a data-tab attribute matching a panel's data-content attribute
  3. Listen for click on the tabs container using event delegation
  4. Remove active class from all tabs and panels
  5. Add active class to the clicked tab and its matching panel
  6. On page load — activate the first tab by default

Flow

User clicks a tab Read data-tab attribute Remove active class from all tabs Remove active class from all panels Add active class to clicked tab Find matching panel by data-content Add active class to matching panel

HTML Structure

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

      /* tab buttons row */
      .tabs {
        display: flex;
        gap: 6px;
        border-bottom: 2px solid #e0e0e0;
        margin-bottom: 20px;
      }

      .tab-btn {
        padding: 10px 20px;
        font-size: 0.95rem;
        font-weight: 500;
        background: none;
        border: none;
        cursor: pointer;
        color: #888;
        /* small gap so the active border lines up with the bottom border */
        border-bottom: 2px solid transparent;
        margin-bottom: -2px;
        transition: color 0.15s, border-color 0.15s;
      }

      .tab-btn:hover {
        color: #333;
      }

      /* active tab — highlighted with underline */
      .tab-btn.active {
        color: #111;
        border-bottom-color: #111;
      }

      /* content panels — hidden by default */
      .tab-panel {
        display: none;
        font-size: 0.95rem;
        line-height: 1.6;
        color: #555;
      }

      /* only the active panel is shown */
      .tab-panel.active {
        display: block;
      }

      .tab-panel h3 {
        margin-top: 0;
        color: #222;
      }
    </style>
  </head>
  <body>
    <h1>Languages</h1>

    <!-- tab buttons — data-tab matches each panel's data-content -->
    <div class="tabs">
      <button class="tab-btn active" data-tab="html">HTML</button>
      <button class="tab-btn" data-tab="css">CSS</button>
      <button class="tab-btn" data-tab="js">JavaScript</button>
    </div>

    <!-- content panels -->
    <div class="tab-panel active" data-content="html">
      <h3>HTML</h3>
      <p>
        HTML stands for HyperText Markup Language. It is the standard
        markup language used to structure content on the web — headings,
        paragraphs, links, images, and more.
      </p>
    </div>

    <div class="tab-panel" data-content="css">
      <h3>CSS</h3>
      <p>
        CSS stands for Cascading Style Sheets. It is used to style and
        layout HTML elements — colors, spacing, fonts, positioning, and
        responsive design.
      </p>
    </div>

    <div class="tab-panel" data-content="js">
      <h3>JavaScript</h3>
      <p>
        JavaScript is a programming language that adds interactivity to
        web pages — handling clicks, form validation, animations, and
        communication with servers.
      </p>
    </div>

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

Solution

// Step 1 — select the tabs container, all tab buttons, and all panels
const tabsContainer = document.querySelector(".tabs");
const tabButtons = document.querySelectorAll(".tab-btn");
const tabPanels = document.querySelectorAll(".tab-panel");

// Step 2 — use event delegation on the tabs container
// one listener handles clicks on any tab button
tabsContainer.addEventListener("click", (e) => {
  // ignore clicks that are not on a tab button
  if (!e.target.classList.contains("tab-btn")) return;

  const clickedTab = e.target;

  // Step 3 — read which tab was clicked from data-tab
  const targetName = clickedTab.dataset.tab;

  // Step 4 — switch to that tab
  switchTab(targetName);
});

function switchTab(targetName) {
  // Step 5 — remove "active" from all tab buttons
  tabButtons.forEach((btn) => btn.classList.remove("active"));

  // Step 6 — remove "active" from all content panels
  tabPanels.forEach((panel) => panel.classList.remove("active"));

  // Step 7 — find the tab button and panel that match targetName
  // [data-tab="..."] selector finds the element with matching attribute
  const matchingTab = document.querySelector(`[data-tab="${targetName}"]`);
  const matchingPanel = document.querySelector(`[data-content="${targetName}"]`);

  // Step 8 — activate both
  matchingTab.classList.add("active");
  matchingPanel.classList.add("active");
}

Code Execution

Trace through clicking the "CSS" tab:

StepCodeResult
Click targete.target<button class="tab-btn" data-tab="css">
Check classe.target.classList.contains("tab-btn")true
Read data-tabclickedTab.dataset.tab"css"
Remove active from tabstabButtons.forEach(...)all tabs un-highlighted
Remove active from panelstabPanels.forEach(...)all panels hidden
Find matching tab[data-tab="css"]CSS button
Find matching panel[data-content="css"]CSS panel
Add activeboth elements get .activeCSS tab highlighted, CSS panel shown

Trace through clicking somewhere that is not a tab (e.g. inside a panel):

StepCodeResult
Click targete.targetsome <p> or <h3> inside a panel
Check classe.target.classList.contains("tab-btn")false
Actionreturn — nothing happensno change

Output

Page loads          → "HTML" tab active, HTML content shown
Click "CSS"         → "CSS" tab active, CSS content shown, HTML hidden
Click "JavaScript"  → "JavaScript" tab active, only JS content shown
Click "HTML" again  → back to HTML content

On this page