Submit your widget

simple Dynamic tabs using jQuery

Created 3 years ago   Views 22560   downloads 2841    Author jankoatwarpspeed
simple Dynamic tabs using jQuery
View DemoDownload 27.8 KB
134
Share |

This example 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.

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?