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


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

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:

<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>
	<li><a href="http://">Typefaces</a></li>
	<li><a href="http://">Painting</a></li>
	<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>
</ul>
</div>
<div id="freebies">
<ul>
	<li><span>a</span><a href="http://">Icons</a></li>
	<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>

The jQuery code

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

//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;
 });
 }
 }

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

jQuery('#block a').get()

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

jQuery('#block a').get()[1]

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

WordPress plugin now available!

You can now purchase on CodeCanyon a widget for WordPress based in the latest version of this code: Rotating Tabs Widget for WordPress to displays your latest posts from categories or tags using the rotating tabs.


“Multiple instances of jQuery Tabs” received 33 comments! Add yours.

  1. Dean September 2nd, 2010

    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. Valera September 6th, 2010

    How to cut off block extinction?
    I push two times the push button and the unit it is closed down.

  3. Elio September 6th, 2010

    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.

  4. Valera September 7th, 2010

    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!

  5. Valera September 8th, 2010

    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;

    });

    });

  6. Elio September 9th, 2010

    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.

  7. Frank September 9th, 2010

    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){

  8. Frank September 9th, 2010

    Here’s the link to the problem : http://gameinterlude.com
    Thought it would display in my last message!

  9. Elio September 10th, 2010

    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 :P

  10. Phil November 11th, 2010

    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}

  11. Elio November 11th, 2010

    Hi Phil, I’ve just changed this line from the demo

    <li><h2><a href="#freebies" id="freebiest" rel="nofollow">Freebies</a></h2></li>
    

    into

    <li><h2><a href="#freebies" id="freebiest" rel="nofollow">Freebies <span>tip</span></a></h2></li>
    

    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.

  12. Phil November 11th, 2010

    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 :)

  13. Elio November 11th, 2010

    Awesome Phil, you rock! just out of curiosity, what was the error message you were receiving?

  14. Optimized rewrite rules for WordPress | The best Tutorials January 14th, 2011

    [...] Multiple instances of jQuery Tabs [...]

  15. Learn how to program with Hackety Hack | The best Tutorials January 16th, 2011

    [...] Multiple instances of jQuery Tabs [...]

  16. chris February 26th, 2011

    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!

  17. Elio March 2nd, 2011

    Chris, if you don’t set a number for speed, it won’t cycle through the different tabs.

  18. chris March 7th, 2011

    And where is the Speed set? – thanks

  19. defencedog April 10th, 2011

    Good work; managed to customise it & integrate widget within a widget. visit http://defencedog.fileave.com/rotatingtabs/rotatingtabs.html

    However how to customise timing of transition

  20. Happynuke May 10th, 2011

    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?

  21. Elio May 10th, 2011

    Hi Happynuke, you might want to try the tabs widget plugin for WordPress that was created for this code.

  22. Happynuke May 10th, 2011

    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.

  23. Elio May 10th, 2011

    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.

  24. garrie May 30th, 2011

    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.

  25. Giuseppe M. August 18th, 2011

    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

  26. Elio August 18th, 2011

    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.

  27. Jon Horton September 1st, 2011

    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:

    Uncaught TypeError: Cannot set property 'reference' of undefined
  28. 23123 | 汽車貸款的專家 – Funabank方便貸 September 17th, 2011

    [...] 23123Published 2011 年 09 月 17 日 | By admin « Go back to Multiple jQuery Tabs [...]

  29. mona September 28th, 2011

    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

  30. Paul October 6th, 2011

    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.

  31. Paul October 6th, 2011

    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!

  32. Elio October 6th, 2011

    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

  33. Paul October 9th, 2011

    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!

Leave a comment