Skip to main content

Multitab menu in HTML 5

How to create a multitab menu in HTML 5? The basic idea is to deal with visibility of the elements.

The basic elements

Let's say we have 2 tabs; each tab is a button element:

<div>
   <button class="tab"> Tab 1 </button>
   <button class="tab"> Tab 2 </button>
</div>
Each tab is associated with a div element as content. We define a common class, such as "content", and an id to distinguish each content:
<div id="1" class="content">
   ...
</div>
<div id="2" class="content">
   ...
</div>
Now, we can use a style (either in HTML code or in a CSS) to hide all elements associated with the class named "content":
<style>
   .content {
      display: none;
      ...
   }
</style>

Visual feedback

To provide a visual feedback, we define a style to show vivid colors when the user move the mouse on a tab (hover). Also, when the tab is selected, the background color goes to white:

   .tab button {
      background-color: #ccc;
      opacity: 0.5;
   }

   .tab button:hover {
      opacity: 1;
   }

   .tab button.active {
      background-color: white;
   }

Managing the tabs

This is now time to manage the tabs and contents. When the user click on a tab, we want all other tab to become inactive; this is achieved with some javascript:

<script>
  function opentab(evt) {
     var i, t;
     t = document.getElementsByClassName("tab");
     for (i = 0; i < t.length; i++) {
        t[i].className = t[i].className.replace(" active", "");
     }
     evt.currentTarget.className += " active";
  }
</script>
Now, we need to call this function on click:
<div>
   <button class="tab" onclick="opentab(event);"> Tab 1 </button>
   <button class="tab" onclick="opentab(event);"> Tab 2 </button>
</div>

Displaying the content

To display the content, we will show the div corresponding to the selected tab. We modify our script to add the id of the content to display:

<script>
  function opentab(evt, cnt) {
     var i, t;
     t = document.getElementsByClassName("tab");
     for (i = 0; i < t.length; i++) {
        t[i].className = t[i].className.replace(" active", "");
     }
     evt.currentTarget.className += " active";
  /* We hide all the elements from class "content" */
     t = document.getElementsByClassName("content");
     for (i = 0; i < t.length; i++) {
        t[i].style.display = "none";
     }
  /* We show all the elements with id "cnt" (usually only one) */
     t = document.getElementsById(cnt);
     for (i = 0; i < t.length; i++) {
        t[i].style.display = "block";
     }
  }
</script>
With the ternary operator, we can compact the code:
<script>
  function opentab(evt, cnt) {
     var i, t;
     t = document.getElementsByClassName("tab");
     for (i = 0; i < t.length; i++) {
        t[i].className = t[i].className.replace(" active", "");
     }
     evt.currentTarget.className += " active";
  /* Hide all "content" elements but the one in parameters */
     t = document.getElementsByClassName("content");
     for (i = 0; i < t.length; i++) {
        t[i].style.display = (t[i].id==cnt)?"block":"none";
     }
  }
</script>
Now, we add the id of the content:
<div>
   <button class="tab" onclick="opentab(event,'1');"> Tab 1 </button>
   <button class="tab" onclick="opentab(event,'2');"> Tab 2 </button>
</div>
It is not necessary to distinguish each tab with an "id"; the event will target only the tab just clicked.

Full code

Here is the full code

<html>
  <head>
    <style>
      .content {
        display: none;
      }
      .tab button {
        background-color: #ccc;
        opacity: 0.5;
      }
      .tab button:hover {
        opacity: 1;
      }
      .tab button.active {
        background-color: white;
      }
    </style>
    <script>
      function opentab(evt, cnt) {
        var i, t;
        t = document.getElementsByClassName("tab");
        for (i = 0; i < t.length; i++) {
          t[i].className = t[i].className.replace(" active", "");
        }
        evt.currentTarget.className += " active";
        t = document.getElementsByClassName("content");
        for (i = 0; i < t.length; i++) {
          t[i].style.display = (t[i].id==cnt)?"block":"none";
        }
     }
    </script>
  </head>
  <body>
    <div>
      <button class="tab" onclick="opentab(event,'1');"> Tab 1 </button>
      <button class="tab" onclick="opentab(event,'2');"> Tab 2 </button>
    </div>
    <div id="1" class="content">
      This is the content of tab 1.
    </div>
    <div id="2" class="content">
      This is the content of tab 2.
    </div>
  </body>
</html>

A more complex example: menu and submenus

In this example, we use 3 levels of menus and submenus

<!DOCTYPE html>
<html>
  <meta charset="UTF-8"> 
  <head>
    <style>
      .content {
        display: none;
      }
      .tab button {
        background-color: #ccc;
        opacity: 0.5;
      }
      .tab button:hover {
        opacity: 1;
      }
      .tab button.active {
        background-color: white;
      }
    </style>
    <script>
      function opentab(evt, str, cnt) {
        var i, t;
        t = document.getElementsByClassName("tab");
        for (i = 0; i < t.length; i++) {
          t[i].className = t[i].className.replace(" active", "");
        }
        evt.currentTarget.className += " active";
        t = str.getElementsByClassName("content");
        for (i = 0; i < t.length; i++) {
          t[i].style.display = (t[i].id==cnt)?"block":"none";
        }
     }
    </script>
  </head>
  <body>
    <div>
      <button class="tab" onclick="opentab(event,document.body,'1');"> Tab 1 </button>
      <button class="tab" onclick="opentab(event,document.body,'2');"> Tab 2 </button>
    </div>
    <div id="1" class="content">
      <div>
        <button class="tab" onclick="opentab(event,document.getElementById('1'),'11');"> Tab 11 </button>
        <button class="tab" onclick="opentab(event,document.getElementById('1'),'12');"> Tab 12 </button>
      </div>
      <div id="11" class="content">
        <div>
          <button class="tab" onclick="opentab(event,document.getElementById('11'),'111');"> Tab 111 </button>
          <button class="tab" onclick="opentab(event,document.getElementById('11'),'112');"> Tab 212 </button>
        </div>
        <div id="111" class="content">
          This is the content of tab 111.
        </div>
        <div id="112" class="content">
          This is the content of tab 112.
        </div>
      </div>
      <div id="12" class="content">
        This is the content of tab 12.
      </div>
    </div>
    <div id="2" class="content">
      This is the content of tab 2.
    </div>
  </body>
</html>

Comments

Anonymous said…
This comment has been removed by a blog administrator.

Popular posts from this blog

Drive replacement for Fostex DMT8-vl

The IDE hard drive on my Fostex DMT8-vl multitrack recorder shows signs of its imminent death; when getting hot, I could not record anymore. Must be said this drive comes from an old Sun Station, and has been replaced because I/O failures were detected by Solaris. It worked at least 5 years in my recorder: not so bad. However, time is now to replace it. The DMT8-vl is not able to handle drives bigger than 8.4 GB. Well, it is able to (the current drive is 15 GB), but only 8.4 GB will be usable. My tought was to use a 8 GB CompactFlash; having no moving parts means no noise, which is quite temptating for a music recording device. I purchased a CompactFlash-IDE adapter on the internet (8$) and I had to build a male-male IDE cable adapter (4$). Unfortunately, this doesn't work. The drive is correctly discovered by the operating system, which proposes to format it ("format IDE?"). After answering "yes", the formating runs pretty fast (faster than on a real drive), ...

Samba: Clients get "system error 1223" (or 123) after a server reboot

Facts: a Linux+Samba server shares anonymously a folder. After a reboot, Win clients could not attach the share drive anymore. C:\>net use \\mylinux\folder Enter the user name for 'mylinux': System error 1223 has occurred. The operation was canceled by the user. C:\>net view \\mylinux\ System error 123 has occurred. The filename, directory name, or volume label syntax is incorrect. The process are present, and tcpdump doesn't provide much information. What's going on? After hours of headscratching, the light came: the firewall was on and no rules for the Samba protocol! Grrr!

Issue with Soundpool MO4

I have a Atari STe with a Soundpool MO4 MIDI extension. It used to work very well, but unfortunatelly doesn't anymore: Cubase still detects it, and I can output MIDI to it but nothing is coming out from any MIDI Out. It took me a while to tackle it (lack of time, lack of tool, other items to play with), but I gave a glance last week-end. The parallel port on the Atari uses only the following signals: Pin 1 : Strobe (Atari -> MO4) Pin 2 : Data 0 (Atari -> MO4) Pin 3 : Data 1 (Atari -> MO4) Pin 4 : Data 2 (Atari -> MO4) Pin 5 : Data 3 (Atari -> MO4) Pin 6 : Data 4 (Atari -> MO4) Pin 7 : Data 5 (Atari -> MO4) Pin 8 : Data 6 (Atari -> MO4) Pin 9 : Data 7 (Atari -> MO4) Pin 11: Busy (MO4 -> Atari) The MO4 also decodes few other pins, but since the Atari doesn't, my guess is the MO4 was also targeted for PC. Inside the box, the MO4 is architectured around a CPLD (IspLSI1016 from Lattice) which contains the logi...