jQuery UI Tabs with browser back button support

In modern day web applications tabs are quite common and users have come to expect that switching between tabs will be stored in the browser history, so pressing the back button will not take him to a totally different page. Also deep-linking should also be possible, so users can bookmark a particular tab on the page.

Initially I thought this would be something trivial, but googling around kind of scared me as the solutions I found were little more involved than I would have liked. Anyway, when I started doing that, I got where I wanted to be without much difficulty. I thought I should share my solution for the benefit of others too.

Note: This solution may have it’s weaknesses, if you spot any please let me know. One possible weakness I chose to ignore was support for very old browsers.

I’m using jQuery and jQuery UI tabs to implement this. I also use Ben Alman’s BBQ library to help me with modifying urls.

First of all you need to create the html markup required for tabs and invoke the tabs plugin to get the tabs.

<div id="tabcontainer">
  <div id="tab1">...</div>
  <div id="tab2">...</div>
  <div id="tab3">...</div>

Then use following code to create the tabs once the document is fully loaded in browser.

function appendHashToLinksInsideTab() {
    //Find all the tabs
    $('div[id^=tab]').each(function (tabindex, tab) {
        $(this).find('a.pageLink, a.sortLink').each(function (index, link) {
            $(link).fragment(tab.id, 2);
// Store the navigation tabs object in a global variable.
var $navigationTabs;

$(document).ready(function () {
    // Modify links inside a tab to contain their respective tab in the fragment

    $navigationTabs = $('#tabcontainer').tabs({
        select: function (event, ui) {
            window.location.hash = ui.tab.hash;
$(window).bind("hashchange", function (e) {
   $navigationTabs.tabs('select', e.fragment);

Here I’m storing the return value of tab in the $navitationTabs variable as we are going to need it later on.
When initializing tabs I pass it an tab-selected event handler, which modifies the hash of the window location each time a new tab is selected. Effectively pushing a new entry into browser history stack.
In my case I’ve lots of sorting/paging links inside each tab. I need to make sure when user clicks in one of these links page re-loads with the same tab selected, otherwise it would be pretty annoying. How I do that is I modify each link to contain their tab ids as the fragment of the link url. appendHashToLinksInsideTab() function does just that.
It first finds all the tab <div>s (all my tabs have ids starting with ‘tab’, ex: tab1, tab2, etc), and find all the sorting and paging links, and modify its href to include the tab.id as the fragment.

$(link).fragment(tab.id, 2);

Second parameter is the merge mode, and value 2 indicates replace any existing fragment with the new value passed, which works in my case.

As the last step we need to monitor the windows hashchange event, and change the selected tab accordingly. Here we use the $navitationTabs global variable to change the selected tab.

$(window).bind("hashchange", function (e) {
   $navigationTabs.tabs('select', e.fragment);

Well, that’s it! Tabs work as intended with back button/sorting/paging. At least on latest versions of IE, FF, Chrome, Safari. I did not have to manually push/pop browser history entries as indicated in some posts.
Hope this helps anyone who is trying to do the same.

Phew!! That was my first blog-post ever!! So please bear with me if I’ve made mistakes, at the same time I welcome any constructive criticism you may have.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: