Dynamic tabs using jQuery – why and how to create it

January 26, 2010

This tutorial will show you how to use jQuery to create tabs that can be added and removed dynamically. Although the example looks bulletproof, there are some questions I will raise about how to use tabs and in which context should they be used in order to make them meaningful and usable.

View demo

When we talk about tabs on web we usually think about tabs used for navigation. However, in this case I’d like to use them in a different context. I want to use them for showing different entities on the same page. By entities I mean anything from plain text to web forms. Actually, I will try to simulate tabs as seen in browsers. Well, at least to some extent. Take Google docs for example, instead of opening each document in a new window (or browser tab), you could open them in page tabs.

Questions

What kind of information makes sense to be shown in page tabs? This is probably the most important question to ask. I would say that you should use page tabs in cases when there is a set of actions that you can perform on all tabs at the same time. For example, you can search and replace text in all tabs with a single action and then save it again with one action. Next, read only information such as text and reports can also be used in this context. But what about web forms? What if I want to create an application that will allow management of different data at the same time? In one tab, I could edit inventory data, while in other I can view related data. Sounds interesting, but seems as if implementation would be too complex. What are your thoughts on this one?

Implementation

Ok, before I raise more questions, let’s see how to create tabs. In this tutorial, we will assume that we have a list of documents that can be opened in separate tabs. Tabs with their content can be removed by clicking on “x” sign located at the right side of each tab. The constraint is that one document can be opened only once.

This is the HTML structure needed for the example. We’ll use rel attribute for creating ids of elements and title attribute to create content. Please note that instead of using title attribute, you can load content in other ways, using Ajax for example.

<div id="doclist">
    <h2>Documents</h2>
    <ul id="documents">
        <li><a href="#" rel="Document1" title="This is the content of Document1">Document1</a></li>
        <li><a href="#" rel="Document2" title="This is the content of Document2">Document2</a></li>
        <li><a href="#" rel="Document3" title="This is the content of Document3">Document3</a></li>
        <li><a href="#" rel="Document4" title="This is the content of Document4">Document4</a></li>
        <li><a href="#" rel="Document5" title="This is the content of Document5">Document5</a></li>
    </ul></div><div id="wrapper">
    <ul id="tabs">
        <!-- Tabs go here -->
    </ul>
    <div id="content">
        <!-- Tab content goes here -->
    </div>
</div>

So, the usage should go like this: When I click on Document1 link, a new tab will be shown with the title “Document1” and content “This is the content of Document1”. It will contain a red cross on the right side of the tab title which will remove the tab and its content.

$("#documents a").click(function() {
    addTab($(this));
});

This code will add a click event on each document link, and will pass the link itself to addTab function.

function addTab(link) {
    // hide other tabs
    $("#tabs li").removeClass("current");
    $("#content p").hide();
    
    // add new tab and related content
    $("#tabs").append("<li class='current'><a class='tab' id='" +
        $(link).attr("rel") + "' href='#'>" + $(link).html() +
        "</a><a href='#' class='remove'>x</a></li>");
    $("#content").append("<p id='" + $(link).attr("rel") + "_content'>" +
        $(link).attr("title") + "</p>");
    // set the newly added tab as curren
    $("#" + $(link).attr("rel") + "_content").show();
}

The addTab function will first hide all tabs (if there are any) and remove class current from all tabs. This class sets a different color for the current tab. Then, it will create a new tab (li element) that will contain a link for tab title and another one for removing the tab. The content is added in a similar way. At the end, the code will set the new tab as current.

So far so good, but this will be pretty much static – we have to add functionality to tabs. When tab header is clicked related content should be shown. Also, when red cross is clicked tab with its content should be removed. For these two scenarios, we will use live method that will bind events to existing elements, but also to all elements that will be added later to HTML dom.

$('#tabs a.tab').live('click', function() {
    // Get the tab name
    var contentname = $(this).attr("id") + "_content";
    // hide all other tabs
    $("#content p").hide();
    $("#tabs li").removeClass("current");
    // show current tab
    $("#" + contentname).show();
    $(this).parent().addClass("current");
});
$('#tabs a.remove').live('click', function() {
    // Get the tab name
    var tabid = $(this).parent().find(".tab").attr("id");
    // remove tab and related content
    var contentname = tabid + "_content";
    $("#" + contentname).remove();
    $(this).parent().remove();
});

The first function will add the content while the second will remove tab content. Now, there are a few more things to do. First, we need to implement a constraint which says that one document can only be opened once. To do so, we will extend addTab function with this code:

// If tab already exist in the list, return
if ($("#" + $(link).attr("rel")).length != 0)
    return;

The last thing we need to handle is the case when a tab is removed. With the current code, no tab will be the current one, and no content will be displayed. What should be done next? In this case I will assume that it will be the best to set the first tab as the current one, although we could also set next or previous one from the one removed.

We need to extend the function that removes the tab with this code (put it at the end of the function):

// if there is no current tab and if there are still tabs left, show the first one
if ($("#tabs li.current").length == 0 && $("#tabs li").length > 0) {
    // find the first tab
    var firsttab = $("#tabs li:first-child");
    firsttab.addClass("current");
    // get its link name and show related content
    var firsttabid = $(firsttab).find("a.tab").attr("id");
    $("#" + firsttabid + "_content").show();
} 

Conclusion 

Although the technical implementation is fine, the main thing you should think about is context. Used in wrong context this can add unnecessary complexity and usability problems. There are also several other things that need to be considered. What if we have large number of tabs? How should this be handled? The way Firefox handles it or some other way? Then, should one tab always be visible (same as Firefox, again)? Then, what about adding new tabs? Should they be added to the end or next to currently shown tab?

What are your thoughts about this? Have you used this concept before and where do you see its usage?

Let's discuss this on twitter.

43 Comments

  • Gaya (January 26, 2010)

    What a great way to explain advanced JS + jQuery! Great article, Janko. This will be useful to many

  • Saud Khan (January 27, 2010)

    I agree with Gaya.

    I also like where you have left it – I can see several useful implementations of dynamics tabs by extending the work from here.

  • Marco (January 27, 2010)

    "li:first-child"
    That’s some very nice use of CSS selectors mate!

    Just one thing: Since jQuery 1.4, you can simply create DOM elements like this:
    $("<span>")
    This gives you a more flexible way of creating elements, than creating it using a full string, like:
    .append("<li class=’current’><a class=’tab’ id …

    Anyway, keep up the great work!

  • Janko (January 27, 2010)

    Thanks for the comments guys! I am glad that you see its usage.

    Marco: That can certainly add more flexibility in creating new elements, thanks for letting me know! I use 1.4inthis example,but I haven’t checked out new features.

  • Michael Lajlev (January 27, 2010)

    Very nice tut, Janko.

    For usability reasons, you should fokus tabs when clicking the menu, even when the tab is open but unfocused.

    Anyone know how you technical do that?

  • jameshd (January 27, 2010)

    Nice tutorial, I shall be nicking your code momentarily. One other question tho, what did you do those wireframes in?

  • Teck Hua (January 27, 2010)

    It reminds me of similar experimental stuff I did some time back (I still need to improve on it)…

    The tabbing mechanisms the modern browsers serve good inspirations for ideas to work on, but it’s gonna be tough to replicate for the html/css/js context. Appending new tab to the end and ‘set focus’ to it will be easier to program, unless there is requirement to do so otherwise. Throw in some horizontal scrolling mechanism when the tabs exceed the containing viewport. Adding dropdown for quick access when there’s simply too much tabs is desirable too.

    The tough parts would be catering for groups of tabsets in a single page (e.g. dashboards), as well as shuffling the tab order within tabset (like a spreadsheeet) & drag/drop tabs amongst other sibling tabsets. There may be situations where the number of tabs/tabsets are not known beforehand (dynamic). Also need to ponder whether it is sound to delete all tabs in a tabset.

    I digress. Maybe in the end what we need is something simple.

  • Janko (January 27, 2010)

    Michael: You have at least one tab in focus, even if you close the one in focus, if that’s what you meant?

    jameshd: Thanks! I made them in ArtRage, the software is rather for artistic painting, but I like it because I have the same freedom as with markers and paper.

    Teck: You didn’t digress at all, I actually like your thoughts. No matter how complex the technical solution would be it should be easy and straightforward for users.

  • Jimit Shah (January 29, 2010)

    Nice Tutorial sir…

  • wespai (January 29, 2010)

    nice collect it to http://ajax.wespai.com

  • dave (January 29, 2010)

    Janko – I think Michael was talking about when you click on a document that is already open. For example, if I click all the links, and all docs are open, and I have focus on Doc5. Then I click the link for Doc3, nothing happens. it would be great if it could focus to Doc3, wherever it is.

  • website laten bouwen (January 29, 2010)

    Used in the right way is think this is great! Maybe not for websites in most cases but for applications it can be great! Very nice script!

  • Janko (January 29, 2010)

    dave: Ah, yes, now I understand, that’s a good point! Thanks!

    website laten bouwen: yep, I guess some types of applications can benefit from this.

  • Justin (January 29, 2010)

    Very interesting idea!

    Just curious, if you put html tags and attributes in the document content (title attribute) will the HTML still validate?

  • Cory Mathews (January 29, 2010)

    This is very nice. I see lots of potential uses (and problems as you discussed) from this. The biggest problem I see with this is having to place all the tabs in the html. Upgrading this to use some nice smooth ajax requests would greatly improve the usability (from a developers POV).

  • moshxsoft (January 29, 2010)

    Nice tutorial ,thanks for sharing

  • Sedat Kumcu (January 29, 2010)

    Thanks for this useful article. Best regards.

  • Daniel Sykes (January 29, 2010)

    This is some good work, thanks for sharing

  • Slipy (January 29, 2010)

    I had seen similar solution before, but it wasn’t so accessible like this. So this is better and more user friendly.

  • sesebian (January 29, 2010)

    Thanks

  • tianhua (January 30, 2010)

    ths,its so great!

  • Design ideas (February 1, 2010)

    Amazing article. Thanks for useful reading

  • SJL Web Design (February 2, 2010)

    Great article, will be hoping to try it out soon!

    thanks for sharing.

  • A-Dubb (February 2, 2010)

    Great tut. Nice.

  • A-Dubb (February 2, 2010)

    When using AJAX to dynamically load content, what happens if javascript is disabled? You never rendered the content to the browser because you planned to dynamically request it at runtime. Thus it wouldn’t be available, correct?

  • Lee (February 3, 2010)

    Awesome stuff! Very useful will tweet for you :)

  • Max (February 4, 2010)

    Great tutorial, as always! Translated it to Russian and added to my tuts world )) at http://ruseller.com/lessons.php?rub=32&id=526

  • Sudhir Kesharwani (February 5, 2010)

    Nice article Janko,

    I am more of a SharePoint professional, and i really see a fantastic use of this example in showing the detailed content in the home page.

    So we can have one web part showing just the titiel of the news/annoucements and then tabbed pages showing the actual contents

    This will surely help in improving the usablity of the site.

    Hats off to you…

    Sudhir Kesharwani

  • TjenePenger (February 8, 2010)

    Awesome tutorial. I’ve been looking for a simple way for a relative noob like myself to ad jQuery to my site – and I don’t think it comes in a much easier package than this to understand. Thanx alot for this very usefull post! Thanx again.

  • felipe saavedra (February 11, 2010)

    muchas gracias..

  • SergioSuperStar (February 16, 2010)

    Hello Janko,

    Long time no hear :-)
    I found this post interesting in technical details.
    One of the problems in terms of usability is what to do when you open new tab. Should you select it or stay on last selected?
    I prefer second case (like in firefox) and not the first one (like in IE).
    But dependent on context first one may apply also (create new document for example).
    Anyway, good work as usually.
    Cheers,

  • vijay (February 20, 2010)

    Hi dude,

    Really great tutorial, then i want to add some div contents instead of the the title text that displayed instead the content div, also it should change dynamically.
    How this can be achieved…

  • Srinivas (February 22, 2010)

    Hi janko,
    I found Your tutorial very much interesting and useful to many of developers.
    Can u help me in my case that, Iam Using 3 frames. one is header,another is left and right frame.

    If we click on link in leftframe, it will add the tab in right frame.and in that tab a webpage will open.

    Please help me in this regard,
    It Is Very Urgent…………..

    Regards,
    Srinivas i

  • Emir Plicanic (February 25, 2010)

    I wrote a similar tutorial using jQuery UI, and yours uses custom built tabs which is great if you don’t want to use additional includes. I am adding a link to this on my tutorial: http://www.emirplicanic.com/javascript/dynamically-add-remove-tabs.php
    Cheers,
    Emir

  • Paul Irish (February 26, 2010)

    You should def get some syntax highlighting going on in your code examples!

  • teorico (March 3, 2010)

    great, thanks…

  • Srinivas (March 3, 2010)

    Hi janko,

    I found Your tutorial very much interesting and useful to many developers.
    Can u help me in my case that, Iam Using 3 frames. one is header,another is left and right frame.

    If we click on link in leftframe, it will add the tab in right frame.and in that tab a webpage will open dynamically.

    Please help me in this regard,
    It Is Very Urgent…………..

    Regards,
    Srinivas i

  • Janko (March 3, 2010)

    Oh, frames… I think it’s best to get rid of frames.

  • billet d’avion (April 7, 2010)

    Jquery tabs are cool but if you only need tabs and nothing else jquery is a quite heavy alternative. A light alternative yetii available here : http://www.kminek.pl/lab/yetii/

  • Preethi (April 9, 2010)

    Hi,

    Your JQuery Tabs look really cool.

    I need to do something very similar to this.

    But m new to JQuery. Can you pls send the complete html doc to my email. And also the s/w requirements to run this file.

    Thanks a Ton !

  • imthiyaz (June 17, 2010)

    Hi janko,

    I found Your tutorial very much interesting and useful to many developers.
    Can u help me in my case that, Iam Using 3 divs. one is header,another is left and right div.

    If we click on link in left div, it will add the tab in right div.and in that tab a webpage will open dynamically.

    Please help me in this regard,
    It Is Very Urgent…………..

    Regards,
    Imthiyaz

  • magori (June 24, 2010)

    very usefull article thanks you

  • Giochi Mario (July 4, 2010)

    Great tutorial even if there is need of some syntax highlighting going on in your code examples