Tutorial

Implementing a Tab Component from Scratch in Vanilla JavaScript

Published on February 24, 2020
Default avatar

By Josh Stoddard

Implementing a Tab Component from Scratch in Vanilla JavaScript

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Sharpen your development skills by recreating the well known tab component using nothing more then vanilla JavaScript and your unflappable wit!

On the surface, tabs may seem quite boring. We all know what they do and use them on a daily basis in our web browsers without giving them much thought, however, designing a modern, reusable tab component that works well on mobile devices using only native browser technologies can actually be quite challenging and is a great opportunity to build some “real world” code.

Base Requirements

Our tab component needs to be:

  • Responsive
  • Reusable
  • Nestable
  • Can set a default tab

Lets get to it! First I’ll start with the code, and then a break down what’s happening:

Markup

Here’s the basic HTML markup for our tab component:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Gator tabs</title>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div class="gator-tabs-container">
    <ul class="gator-tabs-header">
      <li>The nest</li>
      <li class="default-gator-tab">Hello world!</li>
      <li>Rise of the gator</li>
    </ul>
    <ul class="gator-tabs">
      <li class="gator-tabs-container">
        <ul class="gator-tabs-header">
          <li>Nested 1</li>
          <li class="default-gator-tab">Nested 2</li>
        </ul>
        <ul class="gator-tabs">
          <li class="gator-tab">Some eggs in nest one</li>
          <li class="gator-tab">Some eggs in nest two</li>
        </ul>
      </li>
      <li class="gator-tab">Hello world from tab one!</li>
      <li class="gator-tab">Believe me I know tabs, I have the best tabs. Nobody does tabs like I do.</li>
      <li class="gator-tab">For now the eggs lay dormant but soon the gators will rise from the swamps.</li>
    </ul>
  </div>
  <script src="main.js"></script>
</body>
</html>

Styling

And some CSS styles to make it all look good:


  /* minimal reset */
  * {
    margin:0;
    border:0;
    padding:0;
    box-sizing:border-box;
    list-style:none;
  }

  body{
    background-color: #333;
    /* because serifs are gross (IMO) */
    font-family: sans-serif;
  }

  .gator-tabs-container{
    display:flex;
    flex-direction:column;
    width:100%;
  }

  .gator-tabs-header {
    background-color:#DFA612;
    display:flex;
    flex-wrap:wrap;
    padding:.375rem;
  }

  .gator-tabs-header > li {
    color:#fff;
    cursor:pointer;
    flex-grow:1;
    padding:.375rem;
    font-size:1.125rem;
  }

  .gator-tabs {
    display:flex;
  }

  .gator-tab {
    padding:1rem;
    color:#fff;
  }

JavaScript Code

And now let’s let the magic happen with some simple JavaScript:

function tabify( element ){
  const header = element.querySelector('.gator-tabs-header');
  const content = element.querySelector('.gator-tabs');
  const tab_headers = [...header.children];
  const tab_contents = [...content.children];
  tab_contents.forEach( x => x.style.display = 'none');
  let current_tab_index = -1;

  function setTab( index ){
    if( current_tab_index > -1 ){
      tab_headers[ current_tab_index ].style.fontWeight = 400;
      tab_contents[ current_tab_index ].style.display = 'none';
    }
    tab_headers[ index ].style.fontWeight = 800;
    tab_contents[ index ].style.display = 'flex';
    current_tab_index = index;
  }

  default_tab_index = tab_headers.findIndex( x => {
    return [...x.classList].indexOf('default-gator-tab') > -1;
  });

  default_tab_index = default_tab_index === -1 ? 0 : default_tab_index;
  setTab( default_tab_index );
  tab_headers.forEach((x,i) => x.onclick = event => setTab(i));
}

  // this is where the magic happens!
[...document.querySelectorAll('.gator-tabs-container')]
  .forEach(x => tabify(x));

Here’s a screenshot of the app on mobile:

Mobile screenshot of gator tabs

Recap/Breakdown

Our first requirement was to build something responsive and this was easily solved using Flexbox with the flex-wrap property so the tab headers will now stack on top of each other on mobile.

Making the code reusable may seem tricky at first but by wrapping our code into a function called tabify we can make anything into a tab that satisfied the required class/tag structure. This also makes our next requirement, nestable, fall into place automatically.

The last requirement is the ability to set a tab as the default selected when the page opens. This was accomplished by adding the default-gator-tab class to the desired tab header and our script will find the index of the first tab header with this class and use it to set the initial tab.

In a previous article, we described building tabs using React, but honestly, I’m hard pressed to find any significant advantages React has over plain ol’ Javascript in this instance. We’re able to pass any configuration to our script such as the default tab using class names (instead of props) and we are using about the same amount of code as the React version without the overhead of a framework!

If we wanted to, we could easily extend what we have to include animations or more complex feature but I’ll leave that up to you.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Josh Stoddard

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel