jQuery EasyTabs Plugin Update:
Now More Flexible and Usable
I’ve recently made the jQuery EasyTabs plugin more flexible and usable. These updates came out of upgrades to our web app, LeadNuke, which uses it in production on the Feature Tour page (and some internal pages as well). And best of all, thanks to some other optimizations, the EasyTabs plugin is still the exact same size, coming in at just 4KB!
So, without further ado, let’s look at the updates.
Bookmarkable
The EasyTabs plugin now appends the hash for the selected tab to the URL when you click it. And more importantly, if the URL has a hash when the page is loaded and the hash matches one of your tabs, then that tab gets selected. If there is no hash, or if the hash does not match any of your tabs, then the default tab is selected, as before.
Example: http://www.alfajango.com/somepage#second-tab
This means that users can now click a tab, bookmark it or share the link with a friend, and then when that link is clicked, the intended tab gets loaded.
By the way, if for some reason you’d like to disable this feature (as well as the back- and forward-button support below), simply include the new option updateHash: false and the plugin will act exactly as in previous versions.
Back- and Forward-Button Support
When adding the bookmarking functionality, I couldn’t stop myself, so the plugin now supports the browser’s back button when thumbing through tabs. The catch here is that it depends on another jQuery plugin to handle the back- and forward-button events.
I took this route, instead of baking it into the plugin, for two reasons:
- using a separate plugin allows easier cross-browser compatibility even for old browsers that don’t natively support the hashchange event (see explanation here)
- it allows me to keep the EasyTabs plugin ultralight for those who don’t care for this extra functionality.
The good news is that you have your choice of 3rd-party plugins. You can either use the jQuery Address plugin, which is popular, or the jQuery HashChange plugin (recommended), which I like for its simplicity and small size. Either way, just include one of these jQuery plugin files before including the EasyTabs plugin file, and it will just work!
Tab Cycling
Sometimes you want your tabbed content to automatically cycle through the tabs when the page is loaded. EasyTabs now allows you to do that by simply specifying the cycle parameter when calling easyTabs() with the time interval you want between cycles in milliseconds.
For instance, if you want your tabs to cycle every 5 seconds, simply call easyTabs like this:
Cycling will stop if the user clicks one of the tabs manually. Also, if the page is loaded with one of the tabs specified in the URL (you know, with the new bookmarking support), cycling will be disabled.
More Flexible Tab Placement / Structure
This is what really started the update happy-fun-time. EasyTabs was originally conceived to give you maximum flexibility for the HTML structure of your tabs and content. And yet, your tabs had to be in a top-level unordered list <ul>. It seems I focused entirely on flexibility for order and placement of the target content panel <div>s while neglecting the tabs themselves.
Well, that wrong has now been righted. Now there is an optional parameter you can pass in called tabs, which must be a collection of tabs. There, that’s easy enough. By default, the value for tabs is > ul > li. This selector value is relative to your tab container element.
For example, if your tabbed area looks like this:
…then you’d just go with the default value, since your tabs would be selected by #tab-container > ul > li.
But now you can get really creative with your tabs, and nest them deep into your markup if need be…
<div id="some-other-container">
<div id="yet-another-container">
<div class="some-tab-element">
<a href="#tab1">First tab</a>
</div>
<div class="some-tab-element">
<a href="#tab2">Another tab</a>
</div>
</div>
</div>
<div id="tab1">Stuff</div>
<div id="tab2">More stuff</div>
</div>
tabs: '#yet-another-container > .some-tab-element';
});
Previously, the target content <div>s were flexible, and now the tabs themselves are also this flexible. Go nuts!

Thanks for taking the time to write such a great and useful plugin.
I had decided to use your plugin as it has the hash code already included etc.
I do have one problem regarding having a tab which contains a v3 google map.
Before I switched to your plugin I was using the defacto ui.tabs and dealing with the maps issue like this
selected:0,
'select': function(event, ui) {
//this is the href of the tab you're selecting
var currentTab = $(ui.tab).attr('href');
//this is the height of the related tab plus a figure on the end to account for padding...
var currentInner = $(currentTab + '.detail-tab').outerHeight() + 40;
//now just apply the height of the current tab you're selecting to the entire position:relative #tabs ID
$('#tabs').css('height', currentInner);
}
});
/*set the width here to whatever your column width is*/
.ui-tabs-panel{ position:absolute;top:0px; left:0; width:575px;}
.ui-tabs-panel.ui-tabs-hide { display:block !important; position:absolute; left:-99999em; top:-9999em}
How would I incorporate this with your easytabs?
Thanks in advance
fb: Thanks, I’m glad you’re liking it.
It looks like you’re adjusting the height of the tab container to match the height of the active div every time a new tab is selected. You could accomplish the same thing with EasyTabs by doing something like this:
var $this = $(this),
easytabs = $this.data('easytabs'),
activeSelector = '.' + easytabs.opts.panelActiveClass;
// Adjust tab container to height of active panel + 40px
$this.height( easytabs.panels.filter( activeSelector ).outerHeight() + 40 );
}
This code would be separate from the
$('#tabs').easytabs();instantiation.Thanks for the quick response…
Yep that does the job for the auto height but the problem with goggle maps is that it does not like to be hidden during load and then shown afterwards….
so I was hoping for a solution along the lines of when a tab is not selected to not just apply a style of display:none but to actually add to the class of what would normally be the widget-panel in ui-tabs
so tab in view class = ‘ active ‘
tab not in view class = ‘ hide’
so I can load the maps still but have them not on the page as google maps doesn’t like to be loaded into a display:none area…
hope you understand the problem..
also how about having a collapsible option on the tabs in general? ala collapsible: true
sorry for all the questions but these are two things that I honestly think that it would be nice to see available.
And thanks again in advance…
fb: You could load the Google map in the panel container before instantiating EasyTabs, and that should solve the problem of loading it into a
display: nonediv.Also, if you want a class added to the non-active tabs, you could do something like:
var $this = $(this),
easytabs = $this.data('easytabs'),
activeSelector = '.' + easytabs.opts.panelActiveClass;
// Adjust tab container to height of active panel + 40px
$this.height( easytabs.panels.filter( activeSelector ).outerHeight() + 40 );
// Add 'hide' class to non-active panels
easytabs.panels.not(activeSelector).addClass('hide');
// Remove 'hide' class from active panel
easytabs.panels.filter(activeSelector).removeClass('hide');
});
For the collapsable option idea, could you open an issue ticket on github and describe how you’d like it to behave?
Hi,
I ran into the same problem with Google Maps V3 and I solved it by firing a ‘resize’ event after a tab has been clicked.
Add these lines to the ‘easytabs:after’ function:
map.setCenter(myLatlng);
thanks John, just tested and this works well..
Many thanks… I opened a issue ticket on github for you.
Have a great week
In the end I decided to ditch the inline google maps, thanks for your help on that issue anyway.
I have been trying to implement a collapsible action myself and have a test page with the collapsible action implemented very badly (very hacky)…
collapsible
and the rest of the site is without it….
Here is the really hacky code…
$('.page-template-contact-page #tabs li').removeClass('active');
$('.page-template-contact-page #tabs li a').removeClass('active');
$('.page-template-contact-page #tabs li a').live('click',function() {
$(this).toggleClass('active');
$(this).parent().toggleClass('active');
var activeTab = $(this).attr('href');
$(activeTab).animate({height: ['toggle', 'swing']});
return false;
});
$(function(){
hash = window.location.hash.match(/^[^\?]*/)[0];
var tabtoselect = $('.page-template-contact-page #tabs li').find('a[href="' + hash + '"]');
var activeTab = $(tabtoselect).attr('href');
$(tabtoselect).toggleClass('active');
$(tabtoselect).parent().toggleClass('active');
$(activeTab).animate({height: ['toggle', 'swing']});
});
I have tried to get this to work using easytabs:before but to no avail.
Any help greatly appreciated….
And thank you once again for making such a cool plugin
I’d have to really take a close look to figure out what’s going on here. If it’s ok, I’ll try to add this feature into EasyTabs next week, as I think it’s a good idea. I’ll update the issue on Github accordingly and let you know. Thanks for the support!
Thanks for the great plugin!
I’m using easytabs to divide a form into multiple tabs. Switching works great, but since I need to make validation before switching to other tab, I’ve run into problem. I’m calling validation inside the easytabs:before event. Everything works until I want to prevent switching from current tab if validation has failed. Searched documentation, but haven’t found any way to stop tab switching in the easytabs:before event. Is it possible to implement this in some way?
There is currently no way to do this, but I think it’s a great idea. Can you create an issue on Github for this, and I’ll see if I can get to it next week if that’s ok.
Thanks, Steve! I’ve created a new issue on Github. Hope to see this functionality in the nearest future.
Thanks in advance!
I am just wondering if its at all possible to use the following style to create tabs:
Content...
<a href="#tab2" rel="nofollow">Tab 2</a>
Content...
<a href="#tab3" rel="nofollow">Tab 3</a>
Content...
This would leave the markup SEO friendly. I have it a go but my page blew up in my face. I guess the h3′s need to be transformed into a list to make this work.
Cheers,
Steve
That’s a good question. You should be able to do something very similar, like:
<div id="tab1">
Content...
</div>
<a href="#tab2" rel="nofollow">Tab 2</a>
<div id="tab2">
Content...
</div>
<a href="#tab3" rel="nofollow">Tab 3</a>
<div id="tab3">
Content...
</div>
This sort of markup was actually intentional when designing easytabs, and I suppose I can explain the reasoning behind this.
The problem excluding the corresponding
<div>tags is that it’s not semantically correct. The links’hrefattributes are suppose to point to a target, whether it’s another page or an anchor on the page. Without either a<div>tag with a matchingidor another link with a matchingnameattribute, there is no target anchor on the page.To test this out, try loading the markup above in the browser with javascript disabled and click one of the tab links. Notice how the browser jumps to the corresponding div, because it recognizes the target in the page. This is also more SEO friendly, as it provides semantic context in the markup.
Hi Steve,
As you made out, my code didn’t come out as intended. What I actually want to do is have a H2 tag followed by a DIV. The H2 would have the link to show the DIV.
At the moment I do have a H3 before each DIV, but I set a text indentation on them to throw them off the page. When you print the page (using a print style sheet) the H3 and DIVs are show nicely, but the list above is hidden.
I will have another go with the markup you have suggested.
Cheers,
Steve
Hi Steve,
I’m not really a coding guru, and I am trying to get a damn google map to load properly in tab. Can you explain in simple terms how and where this goes in my easytabs call, with regards ‘easytabs:after’ function:
map.setCenter(myLatlng);
…got the basic call:
$('#tab-container').easytabs();
});
…just don’t know how to bind this properly with ‘easytabs:after’.
Many thanks in advance!
Andrew
Hey Andrew, you can bind to the
easytabs:afterevent from within your document ready block. Try this:$('#tab-container')
.easytabs()
.bind('easytabs:after', function() {
google.maps.event.trigger(map, 'resize');
map.setCenter(myLatlng);
});
});
I’m assuming in the above code that the two google maps functions are valid, as I’m not familiar with them.
Hi Steve!
That’s great! Many thanks for the rapid reply!!
: )
It seems to work great! I do have a gallery on this page so now it has a slight flash on loading the images…so that is the next problem…
…can be seen in action here, tabs are at the bottom:
http://www.cheshireandco.co.uk/properties/view.php?id=1
…so does load the google map fine once i moved ALL of the google map code into the easytabs:after function.
Many thanks for your help!
Andrew
You may just want to fire the google maps resizing trigger once, the first time the tab [that contains the google map] is activated:
$(document).ready(function(){
$('#tab-container')
.easytabs()
.bind('easytabs:after', function(evt, tab) {
if ( tab.is('#tab3') && !googleMapsInit) {
google.maps.event.trigger(map, 'resize');
map.setCenter(myLatlng);
googleMapsInit = true;
}
});
});
Steve, I’m looking at using your EasyTabs plugin for a site I am working one. The demo works great and seems to fit the bill for all the features I need.
I just ran your demo page through the dreaded IE test, using IE Tester for IE6 & 7, and with IE9 native (I’m on a Mac). In all those IE cases, when I click on a tab, IE seems to treat it like a standard web anchor and scrolls my page down to the anchor. The issue is when it does that the tab itself is scrolled off screen. Is there any fix for that??
Also to mention, my site is setup with standard jQuery UI tabs right now and in all those same IE checks this behavior does NOT happen.
Hi Molaro, I am also having same issue. Have you found any fix for that? I would appreciate if you will share with us.
Thanks.