Multiple instances of jQuery Tabs

Back in April 3rd, 2009, I wrote a small script to create tabs with jQuery. Many readers liked its simplicity and asked for some more features, like the ability to automatically rotate between each tab and those were into the second incarnation of the tabs. Many more asked through the comments or by email about the posibility to include multiple instances of the rotating tabs and that’s what this release is about. At first I thought about creating a plugin but issuing several calls for each of your tabs made little sense. So it’s built in a way that you only have to issue on call to a tabs() function to activate several tab blocks. For example, the demo initialize the tabs with the following snippet

[js]

jQuery(document).ready(function(){
tabs({
block  : "#block&2000",
block2 : "#block2"
});
});

[/js]

So you only have to call tabs() passing an object as an argument, with properties for each tab block that you want to initialize. The string is the important part. The script will split it using the & character and store two values in an array. The first one will be the block id and the second will be the rotation speed for this tab block in miliseconds. If this parameter is absent the tabs are defined as static. In the example, one of the tabs will rotate and the other will be static.

Check the example for the multiple instance jQuery Tabs.

Markup

The script requires you to enclose the tabs within a div (or a span or a p, since we’re only reading the id attribute). The structure is the following:

[html]
<div id="block">
<h1>Tab Block Title</h1>
<!– titles for each tab –>
<ul>
<li>
<h2><a id="designt" href="#design">Graphic design</a></h2>
</li>
<li>
<h2><a id="developmentt" href="#development">Development</a></h2>
</li>
<li>
<h2><a id="freebiest" href="#freebies">Freebies</a></h2>
</li>
</ul>
<!– tab panels –>
<div>
<div id="design">
<ul>
<li><a href="http://">Typography</a></li&gt;
<li><a href="http://">Typefaces</a></li&gt;
<li><a href="http://">Painting</a></li&gt;
<li><a href="http://">Grid systems</a></li>
<li><a href="http://">Optical balance</a></li>
</ul>
</div>
<div id="development">
<ul>
<li><span>1</span><a href="http://">jQuery rollovers</a></li>
<li><span>2</span><a href="http://">WordPress plugins</a></li>
<li><span>3</span><a href="http://">jQuery slide menu</a></li>
<li><span>4</span><a href="http://">Web development</a></li>
<li><span>5</span><a href="http://">CMS</a></li&gt;
</ul>
</div>
<div id="freebies">
<ul>
<li><span>a</span><a href="http://">Icons</a></li&gt;
<li><span>b</span><a href="http://">Free font giveaway</a></li>
<li><span>c</span><a href="http://">Daxion, Tessa, Merlin</a></li>
<li><span>d</span><a href="http://">DOWNLOAD ME</a></li>
<li><span>e</span><a href="http://">ILC Thickbox</a></li>
</ul>
</div>
</div>
</div>
[/html]

The jQuery code

The code is now larger than previous version but everything is commented for easy understanding.

[js]
//arrays of objects to collect previous and current tab
var previous = [];
var current = [];
//array to store IDs of our tabs
//store setInterval reference
var tablist = [];

//change tab and highlight current tab title
function change(block){
//don’t do anything if it’s the same tab
if(current[block].reference == previous[block].reference) return;
//show proper tab, catch IE6 bug
if (jQuery.browser.msie && jQuery.browser.version.substr(0,3) == "6.0")
jQuery(block + ‘ .tab#’ + current[block].reference).show();
else
jQuery(block + ‘ .tab#’ + current[block].reference).fadeIn();

//clear highlight from previous tab title
jQuery(block + ‘ .htabs a[href=#’ + previous[block].reference + ‘]’).removeClass(‘select’);

//highlight currenttab title
jQuery(block + ‘ .htabs a[href=#’ + current[block].reference + ‘]’).addClass(‘select’);

//hide the other tabs
jQuery("#" + previous[block].reference).hide();
//stores a reference to the current tab in advance for the next iteration or click
previous[block].reference = current[block].reference;
}
function Tab(blockid){
var z = 0;
//stores self ID internally
this.block = blockid;
//function to rotate internal tabs
this.next = function (){
//store references to current and next tab
previous[this.block].reference = jQuery(this.block + ‘ .htabs a’).get()[z].href.split(‘#’)[1];
if(z >= jQuery(this.block + ‘ .htabs a’).get().length-1) z = 0; else z++;
current[this.block].reference  = jQuery(this.block + ‘ .htabs a’).get()[z].href.split(‘#’)[1];
//advance to next tab
change(this.block);
};
}

function Reference(reference){ this.reference = reference; }
function tabs(tobj){

for (key in tobj) {

var params = tobj[key].split(‘&’);
var block = params[0];

//initialize tabs, display the current tab
jQuery(block + " .tab:not(:first)").hide();
jQuery(block + " .tab:first").show();

//highlight the current tab title
jQuery(block + ‘ .htabs a:first’).addClass(‘select’);

//stores reference to first tab when function starts, tab 1 from left to right
previous[block] = new Reference(jQuery(block + " .htabs a:first").attr("href").split(‘#’)[1]);

//stores reference to second tab when the function starts, tab 2 from left to right
current[block]  = new Reference(jQuery(block + ‘ .htabs a’).get()[1].href.split(‘#’)[1]);

//create new Tab object to store values for rotation and setInterval id
tablist[block] = new Tab(block);

//skip if no speed is defined
if (params[1] != undefined) {
//set interval to repeat – next line commented
interid = setInterval("tablist[‘" + block + "’].next()", params[1]);
//store in – next line commented
tablist[block].intervalid = interid;
}

//handler for tab clicking
jQuery(block + " .htabs a").click(function(event){
//store reference to clicked tab
target = "#"+event.target.getAttribute("href").split(‘#’)[1];
tblock = "#"+jQuery(target).parent().parent().attr("id");

current[tblock].reference = jQuery(this).attr("href").split(‘#’)[1];

//display referenced tab
change(tblock);

//if tab is clicked, stop rotating
clearInterval(tablist[tblock].intervalid);

return false;
});
}
}

[/js]

The idea behind is that we create objects for each tab and they operate separately using their internal variables and only accessing a generic change() function to execute the tab rotation, whether it is from the function triggered internally from each object or a user click. The get() function of jQuery was particularly useful. This function makes the matched selectors available as an array, so for instance

[js]jQuery(‘#block a’).get()[/js]

would return all the anchor elements within #block as an array and

[js]jQuery(‘#block a’).get()[1][/js]

would return the second anchor element from that array. Download the file, inspect it closely, play with it, have fun.

38 thoughts on “Multiple instances of jQuery Tabs”

  1. Very smart code. The last section about the get() function was particularly interesting, I wasn’t aware that you could access the selectors like an array.

  2. Oh, it’s true. I never clicked twice on the tab, that’s why it’s so important to conduce different tests. Thanks for the heads up. I’ll be adding a sentence to dismiss the click if the clicked tab is the currently visible tab.

  3. Thanks, well!
    I have already installed a script on a site. But a problem has discovered already now.
    Tried to patch itself but could not.

    I wait for correcting.

    Thanks!

  4. jQuery(document).ready(function(){

    //if this is not the first tab, hide it

    jQuery(“.tab:not(:first)”).hide();

    //to fix u know who

    jQuery(“.tab:first”).show();

    //when we click one of the tabs

    jQuery(“.htabs a”).click(function(){

    //get the ID of the element we need to show

    stringref = jQuery(this).attr(“href”).split(‘#’)[1];

    //hide the tabs that doesn’t match the ID

    jQuery(‘.tab:not(#’+stringref+’)’).hide();

    //fix

    if (jQuery.browser.msie && jQuery.browser.version.substr(0,3) == “6.0”) {

    jQuery(‘.tab#’ + stringref).show();

    }

    else

    //display our tab fading it in

    jQuery(‘.tab#’ + stringref).fadeIn();

    //stay with me

    return false;

    });

    });

  5. Valera, just put this code right after change() function begins:

    if(current[block].reference == previous[block].reference) return;

    This will test if the previously stored tab and the currently clicked tab are the same and will return if they are, thus preventing the panel collapsing.

  6. Thanks for that great tutorial!! I’ve encountered a problem in IE7 (didn’t test in IE6, but I guess I would get the same issue). All tabs are displayed! Do you know what could cause that? Thanks a lot for your help!
    P.S. : Does the fix has to be added after that? //change tab and highlight current tab title
    function change(block){

  7. Frank, you’ve this typo on your code
    tabs({ block : "#block&5000", });
    after the comma, IE 6/7 will be expecting a property and if it is not found, the execution flow will fail. Try removing the offending comma.
    In addition, there’s an error in line 336 popping out. Of course, these nice IE guys won’t be telling you where it is 😛

  8. Who, didn’t know it would take the html tags.. sorry about that.

    Here’s my previous message cleaned up:

    Great script and tutorial!

    There’s just one thing I can’t get working properly: is it possible tu put SPAN tags in the A tags that of the block titles? (The purpose is to do a different styling for the undertitle)

    When I try I get an error message when I click on text located in that span.
    An example:

    {ul class=”htabs”}
    {li}{a href=”#design” id=”designt”}Graphic design{span}Undertitle 1{/a}{/li}
    {li}{a href=”#development” id=”Developmentt”}Development{span}Undertitle 2{/a}{/li}
    {/ul}

    1. Hi Phil, I’ve just changed this line from the demo
      [html]
      <li><h2><a href="#freebies" id="freebiest" rel="nofollow">Freebies</a></h2></li>
      [/html]
      into
      [html]
      <li><h2><a href="#freebies" id="freebiest" rel="nofollow">Freebies <span>tip</span></a></h2></li>
      [/html]
      and worked like a charm. The code you wrote doesn’t have a closing tag for span, make sure you do close it on the code.

  9. Hi Elio,

    Thanks for the response! And yes it actually works, but I get an error message in IE6 and chrome. I just found out a quick way to solve this. The error only occurs when I was doing a rollover the menu item (I changed the click event by a “mouseover”)

    jQuery(block + ” .htabs a”).mouseover(function(event){

    //store reference to clicked tab
    if (event.target.nodeName != ‘SPAN’) {
    ##rest of the code##
    }

    Probably not the best/cleanest solution, but no errors anymore 🙂

  10. hi thanks for the script!- was wondering if there was a way to turn of the auto rotation for the first tab instance? any help would be greatly appreciated – thanks!

  11. I have made this great tab, even i am not that good with these because I also implemented in wp so it is harderr, tab wrap shows eveerything it’s fine but I can’t make the script run, when either tab is clicked to change, i erally don’t know why it’s not working, also if I try another kind of tab it will only work on homepage and not on the rest of the website, can you help me out please?

  12. Thank you for your reply, unfortunately I would consider doing my self and learning how to do these js tricks,if you would like to give me any free info that can be helpful in my problem, with making the tabs work I will gladly appreciate.

    1. It must be some kind of JS issue, but I can’t really tell. Maybe you’re missing some ID or class referencing. Unfortunately, I can’t really help everyone with their own implementation of the tabs in a site. However, if there’s a bug with the demo, and hence the code, I will fix it right away.

  13. Hi,

    Love the script, just a quick question, is there anyway of having a gradient tab as a background image when it goes through it’s auto rotation.

  14. Hi! Great script.. I’m using for featured post in my wordpress theme, but I have a problem:

    when the browser is not active, the tabs keep going to rotate, until all of them became visibile.

    How to solve? thank you

  15. Hi Guiuseppe, you might want to try the WordPress plugin based in a updated iteration of this code, that displays recent posts from any taxonomy, latest comments, tweets and much more. Check it out, I guarantee that you’ll love it.

  16. Thanks for the script, I’ve almost got it working, but I’m unable to switch tabs, although the initial hide all but one panel works fine.

    I’m using jquery1.6.2

    And I get this error when clicking a link: [code]Uncaught TypeError: Cannot set property ‘reference’ of undefined[/code]

  17. i have the second page that’s name is view blog page name at that page have the link back to the blog page in that i am back to the blog page inthat in our porject the blog tab is 3rd tabe when i am back to the index page the blog tab is 3rd tabe so that tab i wan to be selected give me the solution for that

  18. Is it possible to use an image instead of text as a trigger? I’ve been wrestling with this for a few days, but whenever I replace the text with an image the whole thing fails on me. I’ll probably need to just use a plugin, but I’m curious if it’s possible. I like using your code.

  19. Your previous incarnation worked with images. I think I can do everything I need with that one. I wish I had just tried that yesterday instead of persevering!

  20. It still works with images Paul. If you check the demo for the WordPress plugin, built using this code, you’ll see that there are images in the tab content. But then again, I’m wondering if you’re referring to use images for the tabs. In that case, your best bet is to assign the image using CSS, define a fixed width, display: block, and move the text out of the way using text-indent: -99999px;
    Hope it works for you

  21. Yes, I mean using the images as tabs. I did work on a hidden text alternative with a background images, but I have so many thumbnails it would have been unwieldy. Like I said, your previous version of this does work with images (using it now!). Someday when I have more time I will hold the two up and figure out why. The nice thing about the earlier ones is that they were short and simple enough for me to wrap my mind around and extend. I’m sure even my problems with this version will help me be a better coder in the end. Thanks!

  22. Hi ,

    thanks for the script it works like a charm , one issue i have (“may be its just mine :-)” i am not able to add a 3rd instance of the script it gives me a error in the firebug “current[tblock] is undefined
    [Break On This Error]

    current[tblock].reference = jQuery(this).attr(“href”).split(‘#’)[1];”

    PLease help
    Bobin

  23. Hello,
    Thanks for the script it works very well.

    I’m only wondering if there is a way to bookmark the tabs so we could get access through it from an other menu (other page).

    When I use the ID in the URL it’s not working. It takes me only at the first tab instead of the selected one.

    Thanks,
    Juliette Foxtrot

  24. Hello,

    really great script. Works lika a charm but there is no possibility to continue rotating, even after clicking on a tab. I uncommented line ‘clearInterval(tablist[tblock].intervalid);’ but sometimes I find two or three content tabs still displaying. Any solution for this?

Leave a Reply