jQuery Tabs Script With HTML 5 History (PushState)

/ jQuery / by Paul Robinson / 4 Comments
This post was published back on June 19, 2013 and may be outdated. Please use caution when following older tutorials or using older code. After reading be sure to check for newer procedures or updates to code.

You can find quite a few jQuery tabs scripts around the web, including jQuery’s own tabs. However I thought I’d do a little tutorial showing how to build your own, and how to include support for the HTML 5 history system (AKA: PushState).

Important Note

This tutorial will probably get a little complicated. It involves using the HTML 5 history API and some code that jQuery beginners may find confusing.

Also another quick note. This script will only allow 1 set of tabs per page.

jQuery Tabs With HTML 5 History: Demo

So as I know you love a demo, here is one just for you.

jQuery Tabs Script With HTML 5 History

Now that you’ve seen the jQuery Tabs script with HTML 5 History demo, lets get on with how it was built. First let’s start with the HTML.

jQuery Tabs With HTML 5 History: HTML

The HTML for this tutorial is pretty simple. You just need the following:

As I said, the HTML is pretty simple. It consists of an outer container, a unordered list (for the tabs), and a matching set of division tags to hold the data.

It is important to note the data-id, this attribute will be used by our jQuery to identify which box of data to show. Same applies for the hyperlinks in our unordered list. These must match our data-id.

Now that we’ve taken a look at the HTML, let’s take a look at the jQuery.

jQuery Tabs With HTML 5 History: jQuery

This is where things get a little complicated. I’ll try my best to explain it in the simplest terms possible, but if you do have any questions or are confused about anything please drop a comment & I’ll try to help out however I can.

It’s a big block of code, I know, but let’s go through it a bit at a time.

First we have our DOM ready. I normally use this style all the time as force of habit from working with WordPress.

Next we create a couple of variables. The first saves repeating the selector for the tabs & saves memory. The second is to track if we need to use pushState, I’ll explain more soon. The last line checks to see if we have at least one set of tabs before running the rest of the code.

This sets up a click event on our tabs. The click event triggers a function called loadTab() and passes the current clicked elements selector through (as a jQuery object) for the function to use.

Next we setup a popstate event. popstate is triggered when the current browser history is changed such as using pushState (but only in an event such as a click) or when the back button on the browser is pressed. This event just sets our push variable to true and triggers the hashCheck() function, passing the jQuery object containing the tabs to it.

Next the function that we called earlier. hashCheck() tries to split the hash out of the URL. If it finds a hash it activates the correct tab, if it doesn’t it activates the first tab. Now you can grab the hash from the URL using window.location.hash and this gives you the hash with the pound (#) included, but if there is no hash it gives you the full URL. This was no good for my purposes so I decided to use that code instead.

Finally the loadTab function. This function actually loads the tabs when they are clicked. How does it do it? Well like this.

First we remove any active classes that may already be on the tabs. We also hide all of the boxes triggered by the tabs.

Then we grab the hash from the clicked tab. This hash is the one from the hyperlinks I mentioned earlier (remember?). Also if push, our history tracker, is false we need to add this click to the browser history. So we call history.pushState() to add the URL + its hash to the history.

Now we strip the pound (#) from the hash & use it to show the correct box using the data-id attribute to find it. Then we travel up the DOM from the clicked hyperlink to add the active class to the tab. Finally we make sure our push variable is now set to false.

Why Do You Need the push variable?

Well there is a small bug caused by not wanting to repeat any code & that variable fixes it. Because the same function is used to load a tab whether you click it or it is triggered by the popstate event, it will add your going back using the browser history to the history. That means you will never actually go back. It’s a little mind numbing to understand but here is what happens.

  1. You click ‘tab 1’.
  2. You click ‘tab 2’.
  3. You click ‘tab 3’.
  4. You click the back button on the browser. You end up back on ‘tab 2’.
  5. As you go back to ‘tab 2’ the hashCheck function emulates a click on the correct tab (so that the correct tab is loaded) causing pushState to be triggered & a second ‘tab 2’ entry to be recorded.
  6. Now no matter how many times you click the browser’s back button, you are stuck on ‘tab 2’.

Because the push variable allows us to know if the tab was triggered by popstate or a true click we can avoid triggering pushState in popstate cases and avoid this problem completely.

Hopefully that makes sense.

jQuery Tab With HTML 5 History: CSS

I’m not going to include the CSS here, but if you take a look at the demo (look up a little) you can use the CSS from that page just by viewing the page source in your browser. All the CSS on that page is for the tabs & it is just some basic styling I created so feel free to use it as you wish.

jQuery Tab With HTML 5 History: Summary

I basically wanted to show how to make a tab system, but with a twist & I felt the HTML 5 History API added a nice bit of ‘Je ne sais quoi’ to it. Anyway hopefully this has helped you to learn how to create a tab system, and some basics of how to use the HTML 5 History API. I’m just starting out using it myself so if you have any tips you’d like to add or you’ve spotted a mistake please let me know in the comments & I’ll correct it.

I’m aware that this will not work in browsers that do not support the HTML 5’s History API (IE 9 <), but I thought I'd leave that part for you as a little project. I'll give you a hint in that you can either use Modernizer to detect support & disable pushState for browser that don’t support it, or maybe you can emulate the system using some clever JavaScript polyfills/scripts.


Author’s gravatar

Hello, these tabs are perfect! However, just recently I noticed on Chrome the first tab does not load automatically.. The content is empty, until you click on the button.. Before it would load the first tab automatically but now it doesn’t.. Do you know what could be the problem? Thanks!

Author’s gravatar author

Hi Vlad,

It looks as though Chrome may have changed it’s popstate behaviour and no longer triggers it on page load. If this is the case you would simply just need to call the hashCheck() function at the end of the DOM ready. That should trigger the first tab to show on page load.

Author’s gravatar

Hi, There is one issue i.e., when you click on a particular tab mutiple times it will stuck the user on the same state on popstate phase. Need to handle this situation as well.

Author’s gravatar author

Hi Hitesh,

Do you mean that if you click on the same tab multiple times it records those clicks in the history and using the back button appears to do nothing (it does though!)?

If so you could simply add a check to the hashCheck function to check if the tab clicked was the same as the currently active tab and return out. Also please do keep in mind this is quite old now and while it still works there may be ways to improve it do to advances in browser technology.

Older Comments
Newer Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

I'll keep your WordPress site up-to-date and working to its best.

Find out more