// Tutorial //

Implementing a Tab Component from Scratch in Vanilla JavaScript

Published on February 24, 2020
Default avatar
By Josh Stoddard
Developer and author at DigitalOcean.
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:


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

<!doctype html>
<html lang="en">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Gator tabs</title>
  <link rel="stylesheet" href="index.css">
  <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 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 class="gator-tabs">
          <li class="gator-tab">Some eggs in nest one</li>
          <li class="gator-tab">Some eggs in nest two</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>
  <script src="main.js"></script>


And some CSS styles to make it all look good:

  /* minimal reset */
  * {

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


  .gator-tabs-header {

  .gator-tabs-header > li {

  .gator-tabs {

  .gator-tab {

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!
  .forEach(x => tabify(x));

Here’s a screenshot of the app on mobile:

Mobile screenshot of gator tabs


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.

Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

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!