Solution

The solution renders the tab headers and content panels from the given JavaScript array, then wires up click handlers so that only one tab's content is visible at a time and the first tab is active by default. Each .tabs container is initialized independently, so multiple tab groups on the same page work correctly.

HTML

Provide an empty container (or one per tab group). The tab headers and content are created by JavaScript from the tabs array.

<section class="tabs" id="tabs-container"></section>

JavaScript

const tabsData = [
  { id: 'tab-1', label: 'Tab 1', content: 'Content for Tab 1' },
  { id: 'tab-2', label: 'Tab 2', content: 'Content for Tab 2' },
  { id: 'tab-3', label: 'Tab 3', content: 'Content for Tab 3' },
];

class Tabs {
  constructor(container, tabs) {
    this.container = container;
    this.tabs = tabs;
    this.tabHeaders = [];
    this.tabContents = [];
    this.render();
  }

  render() {
    this.container.innerHTML = '';
    this.container.className = 'tabs';

    const headersList = document.createElement('ul');
    headersList.className = 'tab-headers';

    const contentsWrapper = document.createElement('div');
    contentsWrapper.className = 'tab-contents';

    this.tabs.forEach((tab, index) => {
      const header = document.createElement('li');
      header.className = 'tab-header' + (index === 0 ? ' active' : '');
      header.textContent = tab.label;
      headersList.appendChild(header);
      this.tabHeaders.push(header);

      const content = document.createElement('div');
      content.className = 'tab-content' + (index === 0 ? ' active' : '');
      content.textContent = tab.content;
      contentsWrapper.appendChild(content);
      this.tabContents.push(content);
    });

    this.container.appendChild(headersList);
    this.container.appendChild(contentsWrapper);

    this.tabHeaders.forEach((header, index) => {
      header.addEventListener('click', () => this.showTab(index));
    });

    this.showTab(0);
  }

  showTab(index) {
    this.tabHeaders.forEach((header, i) => {
      header.classList.toggle('active', i === index);
    });
    this.tabContents.forEach((content, i) => {
      content.classList.toggle('active', i === index);
    });
  }
}

// Mount into container(s). For multiple tab groups, have multiple empty .tabs elements:
document.querySelectorAll('.tabs').forEach((container) => {
  new Tabs(container, tabsData);
});

// Or a single container by id:
// new Tabs(document.getElementById('tabs-container'), tabsData);

Summary

  • Class: Tabs holds the container, tabs data, and references to the created header/content elements.
  • constructor(container, tabs): Stores container and tabs, then calls render().
  • render(): Builds ul.tab-headers and div.tab-contents from this.tabs, pushes nodes into this.tabHeaders and this.tabContents, attaches click handlers, and shows the first tab.
  • showTab(index): Toggles the active class on the matching header and content so only one tab is visible.
  • Multiple groups: Create one Tabs instance per container (e.g. new Tabs(container, tabsData)), so each tab group runs independently.