Imagine the situation where you have a single-page app. You start playing around with it and after some actions you decide to click the back button from the browser to go back to a previous state.

Do you think your app is prepared for it?

Dealing with browser history can be a headache specially if your app rely on Ajax calls or you have a single page app. Users love using the back button and developers hate it.

The problem with the browser history in Single-Page applications is that the browser is not able to keep track of the states of your application, differently than the traditional multi-page app where every state is usually bound to a different URL.

So what can we do to let users use the back button and at the same time make sure your application won’t break?

If your app uses hashbang #! in the URLs for each state, like twitter used to (http://twitter.com/#!/roshiro), you can restore the previous state with some lines of codes in Javascript. However, hashbangs is not a standard to solve the browser history issue.

That’s where HTML5’s pushState comes in.

Check out a simple example to see how to use pushState feature.

Suppose you have an application to control your restaurant, the code below is the menu. For every plate you click on, its name will be displayed, the URL will be changed and we will store the state of that URL in the browser history.

restaurant_menu.html

<ul>  
    <li><a onclick="burger()">Burger</a></li>
    <li><a onclick="sandwich()">Sandwich</a></li>
    <li><a onclick="fries()">Fries</a></li>
</ul>  
<div id="chosen_plate"></div>  

pushState.js

function burger() {  
  // URL will change to /plate/burger
  history.pushState( { 
    plate_id: 1, 
    plate: "Burger" 
  }, null, "/plate/burger");

  showPlate("Burger");
}

function sandwich() {  
  // URL will change to /plate/sandwich
  history.pushState( { 
    plate_id: 2, 
    plate: "Sandwich" 
  }, null, "/plate/sandwich");

  showPlate("Sandwich");
}

function fries() {  
  // URL will change to /plate/fries
  history.pushState( { 
    plate_id: 3, 
    plate: "Fries" 
  }, null, "/plate/fries");

  showPlate("Fries");
}

function showPlate(name) {  
  document.getElementById("chosen_plate").innerHTML = name;
}

window.onpopstate = function (event) {  
  var content = "";
  if(event.state) {
    content = event.state.plate;
  }
  showPlate(content);
}

It’s important to notice that the URLs don’t need to exist, these “fake” URLs are just a way to link the history entry to its proper state. Then, if you click the back button from your browser, the onpopstate event will be fired which in turn will access the history API and access the stored state and do whatever is necessary, in this example display the name of the plate.

  • onpopstate is fired every time the active history changes.
  • pushState takes 3 arguments, a state object, title (which is currently ignored) and URL.

HTML5’s pushState is great and I see it as a much better and more elegant alternative to hashbangs (#!), which sounds more like a workaround for browsers that don’t support HTML5. So next time you need to manipulate the history of your app, don’t forget to consider using the html5 history API.