khaldoonH
khaldoonH

Reputation: 23

Is there a better way of creating tabs using vanilla JavaScript than this?

I'm trying to create tabs within a webpage using HTML buttons and vanilla JavaScript. I've come up with this solution:

const tab1 = document.getElementById("tab-1");
const tab2 = document.getElementById("tab-2");
const tab3 = document.getElementById("tab-3");
const tabs = [tab1, tab2, tab3];
const tab1Content = document.getElementById("tab-1-content");
const tab2Content = document.getElementById("tab-2-content");
const tab3Content = document.getElementById("tab-3-content");
const tabContents = [tab1Content, tab2Content, tab3Content];

tab1.addEventListener("click", () => {displayTab(tab1, tab1Content)});
tab2.addEventListener("click", () => {displayTab(tab2, tab2Content)});
tab3.addEventListener("click", () => {displayTab(tab3, tab3Content)});

function displayTab(tab, tabContent) {
    for (let i = 0; i < tabs.length; i++) {
        if (tabs[i].classList.contains("active")) {
            tabs[i].classList.remove("active");
            tabContents[i].classList.add("hide");
        }
    }
    tab.classList.add("active");
    tabContent.classList.remove("hide");
}
.hide { display: none }
.active { font-weight : bold }
<h1>Tabs</h1>

<div class="tabBtns">
    <button id="tab-1" class="active">Tab 1</button>
    <button id="tab-2">Tab 2</button>
    <button id="tab-3">Tab 3</button>
</div>

<div class="content">
    <div id="tab-1-content">
        Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dignissimos qui labore, quam dicta voluptate
        libero est blanditiis perspiciatis voluptatibus perferendis velit repudiandae. Maxime, eligendi. Vitae
        magnam similique harum sunt quibusdam.
    </div>
    <div id="tab-2-content" class="hide">
        Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolores similique assumenda reprehenderit eaque
        itaque in magni vero repudiandae, totam maiores saepe iste culpa labore quam esse ipsam fugit cupiditate
        facilis sunt aliquid ad sit voluptatibus veritatis non. Eligendi accusantium libero veniam facere, expedita,
        magnam quia assumenda similique quas, voluptatum nostrum.
    </div>
    <div id="tab-3-content" class="hide">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa, sunt?
    </div>
</div>

Is there a more efficient way of doing this? It feels like it might be a little redundant having to manually add each tab and its content into their respective arrays, and then having to apply an event listener to each manually as well. I would appreciate a more elegant solution if one is possible.

Upvotes: 0

Views: 458

Answers (3)

Mister Jojo
Mister Jojo

Reputation: 22265

You can do that with

  • event delegation
  • data attribute
  • you must also use the classList.toggle() method with its boolean option to add or remove a class,

const buttonsParent   = document.querySelector('div#tab-Btns')
  ,   all_tab_elms    = document.querySelectorAll('button[data-tab], div[data-tab]')
  ;
buttonsParent.onclick = ({target}) =>
  {
  if (!target.matches('button[data-tab]')) return  // ignore other click in this area (like spaces between buttons)
  
  all_tab_elms.forEach( elTab => elTab.classList
           .toggle('active', (elTab.dataset.tab===target.dataset.tab )))
  }
button[data-tab].active { font-weight: bold; }
div[data-tab]           { display: none;     }
div[data-tab].active    { display: block;    }
<h1>Tabs</h1>

<div id="tab-Btns">
  <button data-tab="tab-1" class="active">Tab 1</button>
  <button data-tab="tab-2">Tab 2</button>
  <button data-tab="tab-3">Tab 3</button>
</div>

<div id="tab-content">
  <div data-tab="tab-1" class="active">
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dignissimos qui labore, quam dicta voluptate
    libero est blanditiis perspiciatis voluptatibus perferendis velit repudiandae. Maxime, eligendi. Vitae
    magnam similique harum sunt quibusdam.
  </div>
  <div data-tab="tab-2">
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolores similique assumenda reprehenderit eaque
    itaque in magni vero repudiandae, totam maiores saepe iste culpa labore quam esse ipsam fugit cupiditate
    facilis sunt aliquid ad sit voluptatibus veritatis non. Eligendi accusantium libero veniam facere, expedita,
    magnam quia assumenda similique quas, voluptatum nostrum.
  </div>
  <div data-tab="tab-3">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa, sunt?
  </div>
</div>

Upvotes: 1

Ashley McVeigh
Ashley McVeigh

Reputation: 59

you could make a little function to build your tabs

function buildTab(content, number, etc...) {
  const tab = document.createElement("div")
  tab.innerHTML = content
  tab.addEventListener...
  // whatever else you wanna do
  return tab
}

//json containing all the content you wanna display(?)
const tabs = contentArray.map(c => buildTab(...c))

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370679

Iterate over all tabs and hide them when a button is clicked. Find the index of the clicked button and you can get to the associated <div>, no IDs needed.

const contents = document.querySelectorAll('.content > div');
const buttons = document.querySelectorAll('.tabBtns button');
buttons.forEach((button, i) => {
  button.addEventListener('click', () => {
    buttons.forEach(button => button.classList.remove('active'));
    contents.forEach(content => content.classList.add('hide'));
    button.classList.add('active');
    contents[i].classList.remove('hide');
  });
});
.active {
  background-color: yellow;
}
.hide {
  display: none;
}
<h1>Tabs</h1>

<div class="tabBtns">
  <button class="active">Tab 1</button>
  <button>Tab 2</button>
  <button>Tab 3</button>
</div>

<div class="content">
  <div>
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dignissimos qui labore, quam dicta voluptate libero est blanditiis perspiciatis voluptatibus perferendis velit repudiandae. Maxime, eligendi. Vitae magnam similique harum sunt quibusdam.
  </div>
  <div class="hide">
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolores similique assumenda reprehenderit eaque itaque in magni vero repudiandae, totam maiores saepe iste culpa labore quam esse ipsam fugit cupiditate facilis sunt aliquid ad sit voluptatibus
    veritatis non. Eligendi accusantium libero veniam facere, expedita, magnam quia assumenda similique quas, voluptatum nostrum.
  </div>
  <div class="hide">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa, sunt?
  </div>
</div>

You could also save the index of the last clicked button in a persistent variable instead of looping over each element inside the click handler.

Upvotes: 2

Related Questions