Create a TAB Interface with Browser History and URL support

Introduction

Today, we are going to build a TAB interface. Well, not your ordinary TAB interface, this version come with history support. Yes, you can use Back and Forward button in your browsers, and also it has an URL for each TAB as well.

Sounds complicated? Don't worry, I always make sure my tutorial is simple and quick. We are going to use a plugin called jQuery Address plugin.

With jQuery Address plugin, we can produce virtual addresses that point to a website section. As a result, each TAB content in this tutorial can be bookmarked in a brwoser or social website, or can be sent via email or instant messenger. It also works with browser history and reload button. Tested with IE7, IE8, IE9, FF, Chrome and Safari.

Demo Download

HTML

Basically, we have two sections of HTML.

jQuery TAB Interface with History Support Tutorial
  • #TABS: This section contains TAB items just like a navigation menu. You can set the page title by changing the TITLE attribute of Anchor Tag.
  • #PANELS: This section contains content of each Panel, just like pages. The sequence of the panel must match with the item in TAB. For example, first Tab item displays first panel, second Tab item displays second panel and so on.
<div id="tabs" class="clearfix">
		
	<ul>
		<li><a href="#tab1" title="Tab1 Title">Tab 1</a></li>
		<li><a href="#tab2" title="Tab2 Title">Tab 2</a></li>
		<li><a href="#tab3" title="Tab3 Title">Tab 3</a></li>
	</ul>
		
</div>	

<div id="panels">
	<div class="panel-wrapper">
		<div class="panel">
			<h2>Panel 1</h2>
			<p>Nullam in dui mauris. ......</p> <p>
			<a href="#tab2">Go to Tab2</a></p>
		</div>
		<div class="panel">
			<h2>Panel 2</h2>
			<p>Nullam in dui mauris. ......</p><p>
			<a href="#tab3">Go to Tab3</a></p>		
		</div>
		<div class="panel">
			<h2>Panel 3</h2>
			<p>Nullam in dui mauris. ......</p><p>
			<a href="#tab1">Back to Tab1</a></p>		
		</div>
	</div>
</div> <!-- //#panels -->

CSS

A simple CSS to style up the TAB interface. You can change whatever you want, and selected Tab item is assigned an "active" class.

body {
	font-family:arial;
	font-size:75%;
	margin:10px;
	padding:0;
}

a {
	text-decoration:none;
	outline:none;
}

#container {
	width:600px;
	margin:0 auto;
}

#tabs ul {
	list-style:none;
	margin:0; 
	padding:0;
}

	#tabs ul li {
		float:left;
	}
	
	#tabs ul li a {
		display:block;
		padding:5px 10px;
		font-weight:bold;
		color:#aaa;
		text-decoration:none;
		font-size:120%;
	}		
	#tabs ul li.active a {
		background:#ccc;
		color:#fff;
	}				

#panels {
	width:100%;
	background:#ccc;
}
	#panels .panel-wrapper {
		padding:10px;
	}

	#panels .panel {
		
	}

	#panels .panel h2 {
		margin:0 0 10px 0;	
	}		

.clearfix:after {
	visibility: hidden;
	display: block;
	font-size: 0;
	content: " ";
	clear: both;
	height: 0;
	}
* html .clearfix             { zoom: 1; } /* IE6 */
*:first-child+html .clearfix { zoom: 1; } /* IE7 */		

/*
* CSS3 Styling
*/

#tabs ul li a {	
    border-top-left-radius : 5px;      
    border-top-right-radius : 5px;      		
}
#panels {
    border-bottom-left-radius : 5px;      
    border-bottom-right-radius : 5px;      	
}

Javascript

Thanks for the $.address plugin, it makes this tutorial less complicated. Basically, we have a function called setPanel that choose the correct Tab item and panel. If there isn't hashtag, this function will set everything to default, which is the first Tab item and first panel. Lastly, this function is attached to $.address plugin's init() and change() events.

To ensure you understand how exactly it works, I have put inline comment to explain what it does for each line of code.

var QTABS = {

	init: function () {
	
		// attached onload and change event to address plugin
		$.address.init(function(event) {
			
			// first load, set panel
			QTABS.setPanel(event);
				
		}).change(function(event) {

			// if the url changes, set panel
			QTABS.setPanel(event);			

		});
	
	},
	
	// the core function to display correct panel
	setPanel: function (event) {
	
		// grab the hash tag from address plugin event
		var hashtag = event.pathNames[0];
		
		// get the correct tab item, if no hashtag, get the first tab item
		var tab = (hashtag) ? $('#tabs li a[href=#' + hashtag + ']') : $('#tabs li:first a');

		// reset everything to default
		$('#tabs li').removeClass('active');
		$('#panels .panel').hide();

		// if hashtag is found
		if (hashtag) {
			
			// set current tab item active and display correct panel
			tab.parent().addClass('active');
			$('#panels .panel:eq(' + (tab.parent().index()) + ')').show();			
			
		} else {

			// set the first tab item and first panel				
			$('#tabs li:first').addClass('active');
			$('#panels .panel:first').show();			
		
		}
		
		// change the page title to current selected tab
		document.title = tab.attr('title');
		
	}

}

// Execute this script!
QTABS.init();

Conclusion

That's it, quick and easy. I enjoy create my own jQuery script, but sometimes it just not reasonable to reinvent the wheel. In this case, I used address plugin to speed up the development process. I hope you learn something from this tutorial and found this script useful for your project. If you have any question, drop me a comment. :)

About the Author

Kevin Liew is a web designer and developer and keen on contributing to the web development industry. He loves frontend development and absolutely amazed by jQuery. Feel free to say hi to me, or follow @quenesswebblog on twitter.

Show Some Love, Spread This Post!

12 comments

Peter Mon, 13th February 2012 That's just what I need. But shouldn't there be named anchors like <a name="tabs1"></a> for the link <a href="#tab1">Back to Tab1</a> to work when javascript is disabled?
Reply
Kevin Liew Mon, 13th February 2012 Good idea.
LA Fri, 10th February 2012 This s exactly what I was looking for. Is it possible to add an effect so that the tabs open more smoothly?
Reply
Kevin Liew Sun, 12th February 2012 Smoothly, I guess you want some animation effect, you can add SlideUp, SlideDown effect:

Line 31: $('#panels .panel').stop().SlideUp('500');
Line38: $('#panels .panel:eq(' + (tab.parent().index()) + ')').stop().SlideDown('500');
LA Mon, 13th February 2012 Yes, I am looking for an animated effect. I tried replacing lines 31 and 38 with what you suggested but that didn't do anything.
Andrew Mof Tue, 6th December 2011 Litterly just googling this, is there anyway I can modify your code to load ajax content yet retain the same fucntionality? I would like to be able to use the path in the href rather than javascript...
Reply
Kevin Liew Tue, 6th December 2011 Hi Andrew, yes, it will still work. To show the content, we match the hash tag against the value of the href value, and then show the correct content based on the LI index. You can try, I'm pretty sure it will work.
felipe Sat, 3rd December 2011 I can connect the database tab with forms
Reply
Fanus Tue, 11th October 2011 Correct me if I'm wrong. This method isn't best for making your website SEO friendly. As far as I know, using # in your URLs mean that you use JavaScript AJAX and search engines do not read JavaScript. I might be wrong. I'm working on something similar to this and I went the SEO friendly route. Perhaps someone can provide me with a SEO friendly and Bookmarkable AJAX solution?
Reply
Kevin Liew Tue, 11th October 2011 Hi Fanus, not in this case though :) This is something different, all content need to be populated, so when you switch between tabs, it's just hide and show, no ajax call. Basically, all content has already loaded but hidden by javascript, so SEO won't be an issue at all.
ikkez Tue, 11th October 2011 nice tutroial. but isn't it preferable to use a definion list in the html part for better semantic structure? i thought about something like <dl><dt>tab title</dt><dd>tab content</dd>...</dl>
cheers,ikkez
Reply
Kevin Liew Tue, 11th October 2011 Well, depend on what are you trying to do. Tab interface usually contains complex html structure in each panel. So, DIV would be the best. If you want to make FAQ, Q&A , glossary section, I guess DL, DT and DD would be the best. :)

Leave a comment

Have something to say? Drop a comment! No HTML tags are allowed in the comment textfield.

Advertisement