Search

jQuery Tabs

Posted on 18th January 2008 — Tabbing has been common place on the Internet for some time now. Today web sites will make use of tabbing without the page having to reload with the addition of JavaScript.

For this tutorial I have created two screencasts demonstrating how to quickly apply a dash of jQuery to different layouts of markup, which, if the markup is well designed, it will automatically degrade nicely without JavaScript enabled. In a future article we will cover default browser functionality (i.e. supporting back, forward and bookmark buttons) and saving tab states.

Conventional and simple markup

Watch the jQuery tabs screencast - part 1 (flash version)

(QuickTime version is approx. 25Mb, flash version is streaming)

View demo and code used in screencast

Typical tabbing structure, and the one used in the demo is usually marked up as follows:

<div class="tabs">
  <!-- tabs -->
  <ul class="tabNavigation">
    <li><a href="#message">Send a message</a></li>
    <li><a href="#shareFile">Share a file</a></li>
    <li><a href="#arrange">Arrange a meetup</a></li>
  </ul>

  <!-- tab containers -->
  <div id="message">
    <p>Lorem ipsum dolor sit amet.</p>
  </div>
  <div id="shareFile">
    <p>Sed do eiusmod tempor incididunt.</p>
  </div>
  <div id="arrange">
    <p>Ut enim ad minim veniam</p>
  </div>
</div>

Here’s the jQuery used, though slightly adapted from this screencast:

$(function () {
    var tabContainers = $('div.tabs > div');
    
    $('div.tabs ul.tabNavigation a').click(function () {
        tabContainers.hide().filter(this.hash).show();
        
        $('div.tabs ul.tabNavigation a').removeClass('selected');
        $(this).addClass('selected');
        
        return false;
    }).filter(':first').click();
});

Real World example

Watch the jQuery tabs screencast - part 2 (flash version)

(QuickTime version is approx. 30Mb, flash version is streaming)

View demo and code used in screencast

Chris Mahon requested a tutorial that explained how to apply tabbing to markup that doesn’t follow the above markup convention.

In his case, the tabs were in a different DIV to the tab containers, in addition, one item in the UL wasn’t a tab, but used to link to a different page.

Here’s the jQuery tab code used:

$(function () {
    var tabs = [];
    var tabContainers = [];
    $('ul.tabs a').each(function () {
      // note that this only compares the pathname, not the entire url
      // which actually may be required for a more terse solution.
        if (this.pathname == window.location.pathname) {
            tabs.push(this);
            tabContainers.push($(this.hash).get(0));
        }
    });
    
    $(tabs).click(function () {
        // hide all tabs
        $(tabContainers).hide().filter(this.hash).show();
        
        // set up the selected class
        $(tabs).removeClass('selected');
        $(this).addClass('selected');
        
        return false;
    });
});

Taking it further

These screencasts are really designed to help you understand the thought process and how to go about writing the code for the tabs.

In a future article I will explain how to convert this code to a plugin that can be reused on your projects, and what to watch out for when making the code reusable.

Of course, you can always use the jUI Tabs to accomplish the task if you require more dynamic functionality.

Related screencasts

Demo

If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.

Source Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Tabs</title>
    <style type="text/css" media="screen">
    <!--
		BODY { margin: 10px; padding: 0; font: 1em "Trebuchet MS", verdana, arial, sans-serif; font-size: 100%; }
		H1 { margin-bottom: 2px; font-family: Garamond, "Times New Roman", Times, Serif;}
		DIV.container { margin: auto; width: 90%; margin-bottom: 10px;}
		TEXTAREA { width: 80%;}
		FIELDSET { border: 1px solid #ccc; padding: 1em; margin: 0; }
		LEGEND { color: #ccc; font-size: 120%; }
		INPUT, TEXTAREA { font-family: Arial, verdana; font-size: 125%; padding: 7px; border: 1px solid #999; }
		LABEL { display: block; margin-top: 10px; } 
		IMG { margin: 5px; }

		UL.tabNavigation {
		    list-style: none;
		    margin: 0;
		    padding: 0;
		}

		UL.tabNavigation LI {
		    display: inline;
		}

		UL.tabNavigation LI A {
		    padding: 3px 5px;
		    background-color: #ccc;
		    color: #000;
		    text-decoration: none;
		}

		UL.tabNavigation LI A.selected,
		UL.tabNavigation LI A:hover {
		    background-color: #333;
		    color: #fff;
		    padding-top: 7px;
		}
		
		UL.tabNavigation LI A:focus {
			outline: 0;
		}

		div.tabs > div {
			padding: 5px;
			margin-top: 3px;
			border: 5px solid #333;
		}
		
		div.tabs > div h2 {
			margin-top: 0;
		}

		#first {
		    background-color: #f00;
		}

		#second {
		    background-color: #0f0;
		}

		#third {
		    background-color: #00f;
		}
		
		.waste {
			min-height: 1000px;
		}
    -->
    </style>

	<script src="/js/jquery.js" type="text/javascript" charset="utf-8"></script>
	<script type="text/javascript" charset="utf-8">
		$(function () {
			var tabContainers = $('div.tabs > div');
			tabContainers.hide().filter(':first').show();
			
			$('div.tabs ul.tabNavigation a').click(function () {
				tabContainers.hide();
				tabContainers.filter(this.hash).show();
				$('div.tabs ul.tabNavigation a').removeClass('selected');
				$(this).addClass('selected');
				return false;
			}).filter(':first').click();
		});
	</script>
</head>
<body id="page">
    <div class="tabs">
        <ul class="tabNavigation">
            <li><a href="#first">First</a></li>
            <li><a href="#second">Second</a></li>
            <li><a href="#third">Third</a></li>
        </ul>
        <div id="first">
            <h2>First</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
        <div id="second">

            <h2>Second</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
        <div id="third">
            <h2>Third</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
    </div>
	<div class="waste"></div>
  </body>
</html>

Comments

  1. Vicky On 29th July 2008 at 16:07

    Hi, thanks for the valuable information. Maybe you can help me on a problem? I’m trying to convert the UI tabs to a horizontal position. I’m pretty much there, but I have a problem with flickering in FireFox. I’m pretty sure it’s in the JS code. An example can be seen here http://www.compasswebservices.com/web/billboard/demo.html Any ideas on how to fix this?

  2. Josh On 9th August 2008 at 00:08

    Hi Remy- I’ve found your tuts extremely helpful. I’m not very versed in jQuery, and your blog is a lifesaver for me.

    I’m wondering, would you have any advice about undoing these tabs for a print style sheet? I’ve got a project where I want the tabs for the screen, but I want all the content in the tabs to show when it prints.

    Any help you might be able to provide would be awesome. Thanks again or the tutorials!

  3. Steve On 14th August 2008 at 10:08

    I have a problem. I built a tabbed interface, and it works great in FF and IE, but in Opera 9.5 when you click on the tab, it jumps the the anchor. Can someone tell me how to fix this ASAP???

  4. Trisha On 22nd August 2008 at 18:08

    has anyone found an IE .png fix for this. Ive got this working with a fade effect, pretty cool, but i need to use transparent pngs everywhere. none of the png fixes even the 3 jquery ones will work inside the tab container.

  5. Jay On 12th September 2008 at 04:09

    Having this same issue - bump for Quin’s post…

    Thanks for the tutorial!

    I have one question… I have created 2 instances of this tab-box on the same page. Therefore, 2 divs each containing 3 tabs. The problem is this. When one tab is selected in one box, the “selected” class is removed from the other box and the content gets hidden.

    Is there a way to have more than one div containing tabs that will maintain the “selected” class?

    Many thanks

  6. Remy On 12th September 2008 at 08:09

    @Jay + @Quin - sorry I’ve been a slack, work’s been very busy lately. The solution you need (though I’ve not tested) should work with the following:

    $(function () {
      $('div.tabs').each(function () {
        var tabContainers = $('> div', this);
    
        $('ul.tabNavigation a', this).click(function () {
          tabContainers.hide().filter(this.hash).show();
          
          $('ul.tabNavigation a', this).removeClass('selected');
          $(this).addClass('selected');
          
          return false;
        }).filter(':first').click();
      });
    });

    What we’re doing it narrowing the context of the tabbing functions down to each group of tabs, rather than the entire document. Let me know how you get on.

  7. Jay On 12th September 2008 at 13:09

    Thanks Remy - you are doing everyone else a favor, so a slack you are not.

    I will implement and let you know!

  8. Jay On 12th September 2008 at 18:09

    That definitely worked - brilliant! Thank you Remy!

  9. Jay On 16th September 2008 at 02:09

    Correction, one tiny problem…

    Script works fine except once selected each tab continues to carry the ’selected’ class. Does not remove class from deselected tab menu items. Ideas?

    Thanks

  10. Jay On 16th September 2008 at 03:09

    Nevermind - got it!

  11. Jay On 16th September 2008 at 03:09

    Hah - take it back, don’t have it figured out. HELP!

  12. knob On 17th September 2008 at 13:09

    yes,same happens to me. once selected each tab continues to carry the ’selected’ class. Does not remove class from deselected tab menu items. it changes the display style from block to none and back but navigation isnt working.help please.

  13. Thomas On 24th September 2008 at 04:09

    @Josh - the trick is to put {display: inline !important} in your print style sheet for any elements that might get hidden by jquery.

  14. Yosi On 26th September 2008 at 14:09

    Hi, I got a problem here,The code for method 2,I copy it and it dosen’t work..

    Firebug Write: a is undefined hidden()()jquery.js (line 1406) (?)()()jquery.js (line 1772) grep()()jquery.js (line 1199) filter()()jquery.js (line 1773) multiFilter()()jquery.js (line 1455) filter()()jquery.js (line 326) hide()()jquery.js (line 2957) (?)()()index.htm#About (line 23) handle()()jquery.js (line 2076) (?)()()

    how to fix?

  15. Paul On 3rd October 2008 at 22:10

    Thanks for sharing!

    How would it work if instead of text for the list items, I want to use images. So each tab would have 2 images: an “up” state and a “over” state?

  16. Davel On 10th October 2008 at 14:10

    Great tab ! I have a question: is it possible to view another tab -except the first one- when you enter a page ? Is it possible to do this in the jquery part ? I think so, but i have no clue.

  17. abe On 11th October 2008 at 22:10

    Great tutorials, but when you whistle in too the mic it kills my ears!

  18. Chad On 20th October 2008 at 03:10

    Hi, can you explain what does the filter do please?

    Thanks!

  19. Martin F On 20th October 2008 at 20:10

    Just like Paul stated, Image instead of text, will be great if you could explain, or maybe better; a background image that will resize as the text is longer or shorter.

    Even thought, I think this is going too much off-topic, since this have more to do with the CSS coding than the Jquery.

    Thank you.

  20. Greg M On 23rd October 2008 at 14:10

    Hi,

    Having VERY annoying IE6 problems. I’ve got four tabs of which, the first two work great. The 3rd, however, duplicates the contents and the 4th is pushed way down the page.

    http://www.dekken-development.co.uk/progx_bilite2/

    Please please, someone let me know how to fix this

  21. Julian On 13th November 2008 at 21:11

    Hi,

    Can you tell me how we can select a tab through the URL? No matter what I feed through the URL, its always the first tab which is opened.

    The code is not showing at: http://codedumper.com/otese#13-14,25

    Thank you.

  22. Daevar On 20th November 2008 at 02:11

    Small fix for multiple tabs and solution published by Remy:

    $(function () { $(’div.tabs’).each(function () { var tabContainers = $(’> div’, this); var tabs = $(’> ul.tabNavigation li a’, this);

    $('ul.tabNavigation a', this).click(function () {
      tabContainers.hide().filter(this.hash).show();
    
      tabs.removeClass('selected');
      $(this).addClass('selected');
    
      return false;
    }).filter(':first').click();
    

    }); });

  23. Jay On 8th December 2008 at 22:12

    Hi Remy,

    Can nested tabs be achieved with this approach, if s can you suggest the right approach?

    Thanks!

  24. Biscutty On 8th January 2009 at 23:01

    Real World example IE6 & IE7

    Just got the tabs working correctly in IE using Max’s explanation in one of the posts above. (see below)

    if (this.pathname.replace(/^\//,”) == window.location.pathname.replace(/^\//,”)) {

    The problem I am having now in IE is the page renders the tabContainers before hiding them, giving the page a awkward resizing glitch, anyone figured this or know how i can get only the first tab container to display?

    Thanksyou’s!

  25. aljuk On 9th January 2009 at 13:01

    Hi Remy,

    very pleased to come across your site, it’s just the resource I’ve been looking for.

    Question: I’ve deployed this tab script on a project and it’s perfect. However, the page in question is quite heavy, and during its loading phase the entire contents of all tabs is rendered prior to the script kicking in and hiding the divs. What approach would you recommend for getting around this for seamless loading?

    I’ve set display to none in css for all tab content other than the first, which works but is obviously a total bodge since with js disabled in the browser those tabs’ contents remains inaccessible…

Comments are now closed.