đź›  Tabby: Building Tabby (A Tabbed component)

Hey ,

I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.

Please upgrade (use this link) access this content.

I'm super eager to help you learn more!

đź›  Tabby: Building Tabby (A Tabbed component)

A Tabbed component lets you show and hide contents. They are similar to tabs in your browser, but you use them inside the page.

I call the tabbed component “Tabby” because the word “Tab” can be used to mean too many things. (Like the Tab key, browser Tabs, etc). Plus, “Tabby” sounds more friendly and fun compared to a “Tabbed component”.

Here’s what Tabby looks like:

GIF showing how a tab component works.

Tabby’s HTML

Tabby contains two parts:

  1. The tabs.
  2. The contents of each tab (we’ll call this tab-content).
Tabbed components contains tabs and tab-contents.

Your HTML structure should be similar to this:

<div class="tabby">
  <div class="tabs">
    <button class="tab">Tab 1</button>
    <button class="tab">Tab 2</button>
    <button class="tab">Tab 3</button>
  </div>

  <div class="tab-contents">
    <section class="tab-content">Content 1</section>
    <section class="tab-content">Content 2</section>
    <section class="tab-content">Content 3</section>
  </div>
</div>

One tab (and its corresponding content) must always be selected. We’ll add the is-selected class to the first tab and tab content.

<div class="tabby">
  <div class="tabs">
    <button class="tab is-selected">Tab 1</button>
    <button class="tab">Tab 2</button>
    <button class="tab">Tab 3</button>
  </div>

  <div class="tab-contents">
    <section class="tab-content is-selected">Content 1</section>
    <section class="tab-content">Content 2</section>
    <section class="tab-content">Content 3</section>
  </div>
</div>

Styling tabs (and their tab content)

If a tab is selected, it should be emphasized. There are many ways to do this. For Tabby, I used filter to de-emphasized tabs that are not selected.

/* De-emphasize tabs that are not selected */
.tab {
  filter: grayscale(75%) brightness(0.9);
}

/* Emphasize the selected tab */
.tab.is-selected {
  filter: none;
  background-color: white;
}
Emphasized and de-emphasized tabs.

When a tab is selected, its corresponding tab-content should be displayed. Other tabs are hidden. We can do this with display: none.

/* Hides tab-content when it is not selected */
.tab-content {
  display: none;
}

/* Show the selected tab-content */
.tab-content.is-selected {
  display: block;
}

Switching tabs

If you want to switch to the second tab, you need to:

  1. Remove is-selected from the first tab.
  2. Remove is-selected from the first tab content.
  3. Add is-selected to the second tab.
  4. Add is-selected to the second tab content.
<div class="tabby">
  <div class="tabs">
    <button class="tab">Tab 1</button>
    <button class="tab is-selected">Tab 2</button>
    <button class="tab">Tab 3</button>
  </div>

  <div class="tab-contents">
    <section class="tab-content">Content 1</section>
    <section class="tab-content is-selected">Content 2</section>
    <section class="tab-content">Content 3</section>
  </div>
</div>
Second tab selected.

Switching tabs with JavaScript

When a user clicks on a Tab, you want to switch to the tab they clicked. Here, you need to:

  1. Add event listeners to each tab
  2. Find the tab they clicked
  3. Find the corresponding tab content
  4. Remove is-selected from other tabs to de-emphasize them
  5. Remove is-selected from other tab content to hide them
  6. Add is-selected to the tab they clicked to emphasize it
  7. Add is-selected to the tab content to show it

Adding event listeners

Here, you can use querySelectorAll to select the tabs. Then, you loop through each tab with forEach, and use addEventListener to add an event listener to each tab.

const tabs = Array.from(document.querySelectorAll('.tab'))

tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    // Do something here
  })
})

Finding the clicked tab

If an event fires, it will fire on the tab that was clicked.

tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    console.log(tab)
  })
})
Logs the clicked tab.

Finding the correct tab content

There are two ways to find the correct tab content:

  1. Counting elements.
  2. Designating a target element.

For Tabby, it makes more sense to designate target elements since each tab has their corresponding tab contents. (You’ll learn how to count elements in Carousel).

When we designate a target element, we set an attribute (like data-target) of the tab to the same value as the id of the tab-content. This works because id is unique. There should not be two elements with the same id.

(For Tabby, we use digimon, pokemon, and tamagotchi instead of content-1, content-2, content-3).

<div class="tabby">
  <div class="tabs">
    <button ... data-target="content-1">Tab 1</button>
    <button ... data-target="content-2">Tab 2</button>
    <button ... data-target="content-3">Tab 3</button>
  </div>

  <div class="tab-contents">
    <section ... id="content-1">Content 1</section>
    <section ... id="content-2">Content 2</section>
    <section ... id="content-3">Content 3</section>
  </div>
</div>

When a user clicks a .tab, we get the target from data-target.

tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    const target = tab.dataset.target
    console.log(target)
  })
})
Logs target.

We can find the correct .tab-content with querySelector. As much as possible, we want to use querySelector from Tabby (and not the document).

const tabby = document.querySelector('.tabby')

tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    const target = tab.dataset.target
    const tabContent = tabby.querySelector('#' + target)
    console.log(tabContent)
  })
})
Logs tab content of the selected tab.

Selecting a tab

We need to do two things to select a tab:

  1. Remove is-selected from other tabs to de-emphasize them.
  2. Add is-selected to the tab they clicked to emphasize it.

Here’s a simple way to do these two step:

  1. We remove is-selected from every tab.
  2. We add is-selected back to the clicked tab.
tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    // ...
    tabs.forEach(t => t.classList.remove('is-selected'))
    tab.classList.add('is-selected')
  })
})
Selects a tab.

Notice we used t as an abbreviation for tab in the forEach loop. We used t because we don’t want to overwrite the tab variable. tab is already used for something else; it means the “clicked tab”. If we used tab, we’ll get the two tab variables mixed up.

Selecting a tab-content

We also need to do two things to select a tab-content:

  1. Remove is-selected from other tab content to hide them.
  2. Add is-selected to the tab content to show it.

We can use the same approach:

const tabContents = Array.from(tabby.querySelectorAll('.tab-content'))

tabs.forEach(tab => {
  tab.addEventListener('click', event => {
    // ...
    tabContents.forEach(c => c.classList.remove('is-selected'))
    tabContent.classList.add('is-selected')
  })
})
Selects the tab-content.

That’s it!