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 posts

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. Pragan On 20th January 2009 at 18:01

    Hi,

    thanks for such a neat post! it really helps!

    I have a question(might be simple), I tried having tables inside the div and if I do this, all the other tabs divs are showing up instead of hiding. Am I missing anything here?

    regards Pragan.

  2. Dustin On 23rd January 2009 at 00:01

    I used tabs for a clients website and they asked that it be IE6 compatible, do you know if this is possible?

    Thanks for your help!

  3. brad On 29th January 2009 at 04:01

    Could you possibly explain how to have the previous div fadeOut and the new div fadeIn when clicked. Thanks for any help.

  4. Josh On 7th February 2009 at 16:02

    Is there a way to set the JS code to apply the selected class to an <li> parent tag instead of the a tag? It would look something like this, but it doesn’t work.

    $('div.tabbed ul.sub-header li a').click(function () {
      tabContainers.hide();
      tabContainers.filter(this.hash).show();
      $('div.tabbed ul.sub-header li').removeClass('active');
      $(this).addClass('active');
      return false;
    }).filter(':first').click();
  5. Raj On 11th February 2009 at 09:02

    Can any body tell about the possibility of Creating the dynamic tabs. i need tab to Created when i click on one button .

    Thanks in advance

  6. Nuno Rodrigues On 23rd February 2009 at 18:02

    I used the second version, and the click works…the thing is the conteiners are not hidden at the beggining. the containers appear and after i click they disapear and only the clicked on appears.

    But why do the containers not hide at first?

  7. Rick On 26th February 2009 at 13:02

    First off, thanks for a great resource (and it’s always nice to here a fellow Brit on the other end of a screencast!). Great stuff. But I’d like to join with Julian (way up there at Nov 08) in asking how to link (via a regular href anchor, whether on the same page or elsewhere) to content that is inside a tab. Can this be done? Putting content into tabs is wonderful for saving space on a long page, but if I can’t link to anything inside a hidden tab then its usefulness is severely limited.

    As Julian pointed out, the CodeDumper link no longer works, so would it perhaps be possible to include the solution on this page (here in the comments, or as an update)? That would be smashing.

    Thanks again.

  8. Remy Sharp On 26th February 2009 at 14:02

    Hi Rick - cheers for the feedback.

    I just remembered that I had undelete functionality on codedumper.com - so I’ve revived the code: http://codedumper.com/otese#13-14,25

    Give it a try - if doesn’t do the trick, come back and let me know (or you can also try the #jquery channel on irc.freenode.net).

  9. Rick On 26th February 2009 at 15:02

    Thanks for putting that code back Remy; it’s not working for me, but that means nothing — I’m a pure noob at javascript and am entirely unsure what I’m doing. I tried to insert the relevant hooks specific to my markup into the code provided but probably did something wrong.

    I’m hesitant about cluttering up the comments with project-specific code though (no fun for anyone else) so is there any chance we could get it working off-blog? I’d happily report back here with the results afterward if it would benefit others.

    Thanks again for your help so far.

  10. Rick On 26th February 2009 at 16:02

    Update: I modified the script with the markup variables so that the tab function is now back… so some success there. But clicking through to content in a hidden tab is not working. So something ain’t right.

  11. osb On 19th March 2009 at 16:03

    This does not work with later versions of jquery.

  12. Ben Spencer On 3rd April 2009 at 11:04

    Hi there,

    Have used this script a few times and love it - thanks a lot. I now need some assistance to tweak it a little if possible.

    What code would I need to implement to make the tabs automatically rotate after a set period of time? Like this: http://stilbuero.de/jquery/tabs_3/rotate.html

    I could obviously just use that, but would prefer to stick to the more lightweight solution here.

    Thanks a lot,

    Ben

  13. Justin Frydman On 1st May 2009 at 00:05

    Here is the correct code to work with the latest version of jquery (1.3.2 as of writing). Excellent tutorial otherwise. Thanks for the hard work.

    $(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();
                });
    

  14. sankar On 7th May 2009 at 05:05

    HI,

    Yes its ie 6 compatible but you need to give inline style for border

  15. Trisha On 25th May 2009 at 05:05

    Thanks man. I tried this a bunch of different ways and nothing worked out of the box but yours. Just a little css editing and im good to go! thanks for sharing cool info like this.

    Trisha

  16. Ian On 27th May 2009 at 07:05

    Thanks for such a brilliant tutorial which gives a really clear explanation of the function. I also learnt a bunch of stuff about the firebug console to boot!

  17. Sam Bennett On 2nd June 2009 at 18:06

    Hi great videos. Soon I shall be using this in my site however it will be a bit more complicated as I will be including pages as there is a lot of content. The only problem is on the second video I noticed a mistake. When you refreshed the page all the tabs were there and not just the first one like the first video. Would you be able to update the code so that it will hide the other Divs and show just the first one?

  18. Stefan On 5th June 2009 at 16:06

    Great tutorial, thank you very much. Is is possible to fade out the content before the new fades in? I am absolutely new to jQuery, so I would be very happy if someone could help me. Thank you very much in advance! :-)

  19. Rob Johnson On 7th June 2009 at 00:06

    Great tutorial, very simple yet very effective thank you very much! Great job!

  20. Simon Kenyon Shepard On 7th June 2009 at 19:06

    I’m a big fan of these remarkably elegant solutions, they really do make an interface that much more intelligent, I do however think there is a problem in that hiding content like this is actually bad for user experience if one comes from a search engine searching for hidden content.

    I wrote a blog post about it a few months ago:

    A fundamental problem with Ajax websites and hiding content

    and created a follow up suggestion for a solution to deal with these problems:

    smartTabs :: SEO friendly AJAX tabs

  21. Wes On 14th June 2009 at 07:06

    Something I think is important to note is how to refocus a tab from a text-link. There is very little on the internet about it, but the answer is quite simple.

    
    $(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('active');
        $(this).addClass('active');
    
        return false;
    
    
    });
    
    //this will filter and assign the correct tab per #example in the url.
     $(tabs).filter(window.location.hash ? '[hash=' + window.location.hash + ']' : ':first').click();
    
          });
    }); 

    Thanks so much for what you do!

  22. Chris On 14th June 2009 at 21:06

    @Wes

    Would this replace all of the javascript in the original code? You’ll have to forgive me, I’m a JS noob. I tried replacing the original and the tabs didn’t render correctly. Do you have a working example of these tabs that work with text links?

    Thanks,

    Chris

  23. Michael On 18th June 2009 at 01:06

    Hi there, fantastic video and technique. We have the same need as Josh above, that is when the anchor is clicked, the ’selected’ class is instead applied to the parent <li> element. Is anyone able to suggest the appropriate code modifications?

  24. james On 18th June 2009 at 23:06

    Hmmm, I have tried with with my page but keep getting an error in firebug: $ is not defined member_home.html()()

  25. Daniel Rae On 24th June 2009 at 15:06

    Hi, is there a workaround for this to allow two sets of tabs on the one page? Obviously changing the names of the anchors in each goes some way to solving it, but the JS used here only allows one DIV to be visible. With two sets of tabs, I’d need two to be visible.

    Many thanks!

Leave your own comment
  • http://