April 20, 2015 9:59 pm

How to Manipulate web browser’s history API for SPAs

Manipulating the browser’s history can be quite useful when you are creating a single page application which relies exclusively on AJAX to show different content. You can manipulate the browser’s history to tell the user’s browser that the user is located on a different page despite the fact that he is not and you can catch requests to that URL so the user can share the content he is currently viewing.

How to Manipulate web browser's history API for SPAs

This enhances the user’s experience by enabling him to come back to particular parts of your SPA whenever he wants and to share particular content from your website with the people in his circle.

Browser support

The new additions to the History API – history.pushState, history.replaceState and history.popState were added with HTML5 but have a pretty decent support globally. Internet Explorer 10 and above supports them, Chrome and Firefox 31 and above supports the methods, as well as Opera 27+ and Safari 7+. They run on the native Android browser with version 4.3+, iOs Safari 7.1+ and Android’s Chrome browser 41+.

Session history management for SPAs

We will create a basic SPA to show the implementation of a SPA that has many pages and look like a normal web app.

First, we create our index.html with a menu and some dummy text.

Then, we create a partials directory and add 3 pages: clients.html, contact.html and products.html

Here is how one of the partials look like:


Now, for the fun part:

We create a function that loads the partials with an ajax call. It takes as arguments the partial that it should load (the page).

history.pushState takes three arguments – the first is an object or other variable that would be passed to your handler for an onpopstate event. Onpopstate is triggered whenever the user uses the browser’s back button and attempts to go to the previous page – in that case you would want to add a listener for onpopstate¬†events and show them the page they desire. Your onpopstate handler would be passed an event object which would have in it the first argument that you passed to history.pushState().

The second argument of pushState is the title and the third represents the manipulation of the URL that you want.

In our case, we want to add a hash with the page/partial’s name.

Next, we loop over each anchor in the document (you could loop over each anchor in some div or other container if you want), get the data-page attribute of the anchor and load the partial named after the value of data-page by calling our loadPartial() function. We pass the page to the loadPartial function.

Then, we catch any popstates and call loadPartial:

Notice that some versions of Chrome trigger popstate when the page is first visited with a null evt.state so first we check if evt.state.page exists. Then, we load the partial (the object we passed as a first argument was called page so we could find at evt.state.page).

Finally, when the page is first opened we check if there is a hash in the URL and if there is we try to load the partial with that name:

Now, users can both open links, experiencing a website with pages and they can also go back and forth between our pages or share their URLs so others could see the exact same content your users wanted them to see (not the homepage)


I hope now you have seen how to make SPA that are more usable and that provide better user experience. Have you ever used the History API before to make this kind of SPAs? What did you built?

If you are planning on building something using this technique, I would be very happy if you share what you have built with me here in the comments.

Author Ivan Dimov

Ivan is a student of IT, a freelance web designer/developer and a tech writer. He deals with both front-end and back-end stuff. Whenever he is not in front of an Internet-enabled device he is probably reading a book or traveling. You can find more about him at: http://www.dimoff.biz. facebook, twitter

Tutorial Categories:
  • Will Abbott

    whats the ‘add’ there for in the second argument of loadPartial()?