Building a Dynamic Tabbed Sidebar Using JQuery

In the release notes for version 3.5.0 of Suffusion I mentioned that native tabbed sidebar support was added. Since I am quite proud of the technique I used to get this effect, I decided to write a tutorial on how to do it. But first I would like to pay homage to the following that helped me visualize the solution:

  1. How To Create Tabs Using JQuery – This article by Justin Tadlock, the creator of the awesome Hybrid Theme, was something I used for version 2.0 of Suffusion, where I introduced the tabbed options panel of Suffusion.
  2. Widget container HTML (and missing titles) – A thread on the WP forums started (and resolved) by DigitalNature, the creator of the Mystique and some other popular themes, regarding an issue with widgets that do not have titles

The Foundation

If you go through Justin’s tutorial you will get the basic gist of how to build a tabbed box. Basically you need to set up 3 things:

  1. The HTML markup
  2. The CSS
  3. The JQuery for the actual tab effects

The HTML markup requires your page’s source code to look similar to this (like Justin’s example, the differences being in the way I named my classes):


<div id="sidebar" class="tabbed-sidebar">
	<!-- The tabs -->
	<ul class="sidebar-tabs">
	<li id="t1" class="sidebar-tab t1"><a class="sidebar-tab t1" title="Tab 1">Tab 1</a></li>
	<li id="t2" class="sidebar-tab t2"><a class="sidebar-tab t2" title="Tab 2">Tab 2</a></li>
	<li id="t3" class="sidebar-tab t3"><a class="sidebar-tab t3" title="Tab 3">Tab 3</a></li>
	<li id="t4" class="sidebar-tab t4"><a class="sidebar-tab t4" title="Tab 4">Tab 4</a></li>
	<ul>

	<!-- tab 1 -->
	<div class="sidebar-tab-content sidebar-tab-content-t1">
	<!-- Put what you want in here.  For the sake of this tutorial, we'll make a list.  -->
	<ul>
		<li>List item</li>
		<li>List item</li>
		<li>List item</li>
		<li>List item</li>
		<li>List item</li>
	</ul>
	</div>

	<!-- tab 2 -->
	<div class="sidebar-tab-content sidebar-tab-content-t2">
	<!-- Or, we could put a paragraph -->
		<p>This is a paragraph about the jQuery tabs tutorial.</p>
	</div>

	<!-- tab 3 -->
	<div class="sidebar-tab-content sidebar-tab-content-t3">
	<!-- Or, we could add a div -->
		<div>Something needs to go in here!</div>
	</div>

	<!-- tab 4 -->
	<div class="sidebar-tab-content sidebar-tab-content-t4">
	<!-- Why not put a few images in here? -->
		<p>
			<img src="image.gif" alt="Sample" />
			<img src="image.gif" alt="Sample" />
			<img src="image.gif" alt="Sample" />
		</p>
	</div>

</div><!-- tabbed-sidebar -->

Now for the JQuery code to run this:


$j = jQuery.noConflict(); 

$j('div.tabbed-sidebar ul.sidebar-tabs li:first').addClass('sidebar-tab-first');
$j('div.tabbed-sidebar div.sidebar-tab-content:first').addClass('sidebar-tab-content-first');
$j('div.tabbed-sidebar div.sidebar-tab-content').hide();
$j('div.sidebar-tab-content-first').show();
$j('div.tabbed-sidebar ul.sidebar-tabs li.sidebar-tab-first a').addClass('tab-current'); 

$j('div.tabbed-sidebar ul.sidebar-tabs li a').click(function(){
	var thisClass = this.className.substring(12, this.className.length);
	$j('div.tabbed-sidebar div.sidebar-tab-content').hide();
	$j('div.tabbed-sidebar div.sidebar-tab-content-' + thisClass).show();
	$j('div.tabbed-sidebar ul.sidebar-tabs li a').removeClass('tab-current');
	$j(this).addClass('tab-current');
});

The above code simply does the following:

  1. Adds the classes “sidebar-tab-first” and “sidebar-tab-content-first” to the tab and content. We could have done this directly in our markup, but the reason for doing it in JQuery will soon become clear.
  2. Hides all “content” divs, shows the first content div (with class sidebar-tab-content-first), then adds the “tab-current” class to the first tab (with class sidebar-tab-first)
  3. Adds a click function to each tab, making it display the associated content by determining the class of the tab.

So Where is the Problem?

So far we have done something fairly simple for a person with basic JQuery knowledge. The problem lies in tying this with dynamic sidebars. Consider the fact that the definition of a sidebar requires the following parameters:

  1. $before_widget
  2. $after_widget
  3. $before_title
  4. $after_title

These are parameters that apply to the creation of individual widgets, not the overall sidebar. If you notice our HTML markup in the previous section, we have created separate sections with all the tabs isolated from the content. But this is not possible for widget definition!! In other words, the widgets print one after the other, so each tab (i.e. the title of a widget) is grouped with the body of the widget, followed by the tab for the next widget and its body, etc. In WP-speak, the widgets typically print $before_widget, then $before_title, then the title, then $after_title, then the content and finally $after_widget. Or course there is nothing preventing a widget author from going bonkers and messing up the order, or not using one of the tags above etc. But that is the widget author’s problem. Assuming that the widgets are coded in a standard fashion, the code doesn’t quite render in a way conducive to tabbed sidebars.

The Fix

The fix is intuitive and is wholly borrowed from the WP forum post I lined to in the above. First we register the sidebar with parameters as follows:

  1. before_widget: ‘<li id="%1$s" class="sidebar-tab %2$s"><a class="sidebar-tab">’
  2. after_widget: ‘</div></li>’
  3. before_title: ” (a blank)
  4. after_title: ‘</a><div class="sidebar-tab-content">’

Note the following:

  1. We are creating the content as a “div” object within the “li” object.
  2. We are unable to assign the widget class (“%2$s”) or the widget id (“%1$s”) to the “a” element.

Now we will pull a trick using JQuery. We will modify the JQuery code thus:


$j = jQuery.noConflict();

$j('.sidebar-tab .sidebar-tab-content').each(function() {
	var parentId = this.parentNode.id;
	var parentClass = this.parentNode.className;
	parentClass = parentClass.substring(12);
	$j(this).addClass('sidebar-tab-content-' + parentId);
	$j(this).addClass(parentClass);
	$j(this).appendTo(this.parentNode.parentNode.parentNode);
}); 

$j('.tabbed-sidebar ul.sidebar-tabs a').each(function() {
	var parentId = this.parentNode.id;
	$j(this).addClass(parentId);
});

$j('div.tabbed-sidebar ul.sidebar-tabs li:first').addClass('sidebar-tab-first');
$j('div.tabbed-sidebar div.sidebar-tab-content:first').addClass('sidebar-tab-content-first'); 
$j('div.tabbed-sidebar div.sidebar-tab-content').hide();
$j('div.sidebar-tab-content-first').show();
$j('div.tabbed-sidebar ul.sidebar-tabs li.sidebar-tab-first a').addClass('tab-current'); 

$j('div.tabbed-sidebar ul.sidebar-tabs li a').click(function(){
	$j(this).removeClass('tab-current');
	var thisClass = this.className.substring(12, this.className.length);
	var parentId = this.parentNode.parentNode.parentNode.id;
	$j('#' + parentId + '.tabbed-sidebar div.sidebar-tab-content').hide();
	$j('#' + parentId + '.tabbed-sidebar div.sidebar-tab-content-' + thisClass).show();
	$j('#' + parentId + '.tabbed-sidebar ul.sidebar-tabs li a').removeClass('tab-current');
	$j(this).addClass('tab-current');
}); 

What we did is this:

  1. After the page was loaded, we moved the “sidebar-tab-content” objects out of the “li” objects and appended those to the “sidebar-tabs” list as a whole. We did this by smart use of the JQuery “appendTo” function to add every tab’s content to its grandparent.
  2. Did all the necessary class additions that we couldn’t in our widget setup, again by fetching it from the parent / grandparent and using the “addClass” function.
  3. Added other necessities like the classes for the first tab etc.

That’s basically it. The JavaScript neatly rearranges our code into something conducive for tabbing, then applies the tabbing effects.

Is Everything Hunky-Dory?

Maybe. Let’s first see what advantages it gives us:

  1. You are not constrained by a rigid framework. Most of your widgets will seamlessly tie in with this sidebar.
  2. With a little extra effort you can make every sidebar behave this way without repeating this code. You just have to be smart with the sidebar ids and use them while doing the hide/show.

Now let’s first examine cases where the tabbing will not work:

  1. If your widget has no title, obviously there is no handle for the content in the tab-bar and the result is not pretty. This is not a shortcoming of the code – it is more like a user error. Imagine looking for a document without a title.
  2. If a widget author has not followed standard WP guidelines and has ignored the $before_title and $after_title tags and decided to specify his own, that too will cause issues, because the JQuery is relying on certain classes to be named in a certain manner. As I mentioned in the previous section, this is really bad coding on the part of the widget author.

Lastly let’s see what the pitfalls are:

  1. If your page is not using JQuery currently, adding this capability will require it to do so. That might slow your page down.
  2. If you have a lot of content on your page and if your images are heavy, the JQuery code will be the last to load. While your page is loading the users will see a haphazard layout of the sidebar and once the script is executed at the end of the page load the layout will click in place.

That’s about it. If anyone has a better approach do let me know.

6 Responses to “Building a Dynamic Tabbed Sidebar Using JQuery”

  1. Thanks for this article! I’m going to try and implement this onto my site later.

  2. Hi,

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

    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

  3. sir i want to drag my whole ul and when i hover that ul in other tab the other tab should open and then i can put that ul in other tab.
    how is this possible.
    i want the coding for it in jquery.
    Hoping for the best…

    Regards
    Bipin

  4. You left out one important step — you didn’t show us how to add your new “widget” to the WordPress widgets menu!

    • Well, that is because this is not a widget at all. I have by the above method made the sidebar itself tabbed, irrespective of the widget added. So if you add almost any widget to the sidebar, you will automatically see it show up in a tab.

  5. Thanks, this was really helpful