HTML5 slowly releases all its beauty. Before HTML5 one thing which was almost completly out of our control was  the browser history manipulation without full page reload (location.hash hacks are not counted here). With appearence of HTML5 History API all things changed, now it is possible to add elements to the history, add navigation handlers and more.  This time I am going to dive into HTML5 History API.

# History API basics

History APS bases on the single DOM interface - History object. Each browser tab has its own unique History object, which is accessible  in window.history.

History has a number of methods, events and properties that we can control from JavaScript. Each page of the browser tab (Document object) is a collection of History objects.

Each element of the history consist of URL, state of the object (state object), can have a title, document object, form data, scroll position and other information related to the page.

The main methods of the History object are:

  1. window.history.length: Number of entries in the current session history
  2. window.history.state: Returns current history object
  3. window.history.go(n): Method allows to walk through history. The argument passed is the offset the current position. If you pass 0, the current page will be updated. If the index goes beyond the history, nothing happens.
  4. window.history.back(): The method is identical to calling go(-1)
  5. window.history.forward(): The method is identical to calling go(1)
  6. window.history.pushState(data, title [, url]): Adds an element to the history
  7. window.history.replaceState(data, title [, url]): Updates the current element of history
To go two steps back in history you can use:

history.go(-2)

To add elements of history, you can use history.pushState:

history.pushState({foo: 'bar'}, 'Title', '/baz.html')

To change the history records we can use history.replaceState:

history.replaceState({foo: 'bat'}, 'New Title')

Live example

Now we know the basics, let's look at a live example. We will do a web file manager, which allows you to find the URI of selected image (look what you get in the end). The File Manager uses a simple file structure that is written in JavaScript. When you select a picture file or folder is updated dynamically. image

We use data-* attributes to store the header of each image and use the property dataset for this property:

<li class="photo"> <a href="crab2.png" data-note="Grey crab!">crab2.png</a> </li>

To get everything working quickly we load all the pictures and update the src attribute dynamically. But, this acceleration creates a problem - it breaks the back button, so you can not go by pictures forward or backward.

HTML5 history comes to the rescue!

Every time we choose a file new history record is created and document location is updated(it contains a unique URL of the image). This means that we can use the back and forward button navigate through then our images, while in the address bar, we have a direct link to the picture that we can save a bookmark, or send someone else.

# Demo code

We have 2 divs. One contains a folder structure, the other contains the current picture. Here I will show only the most important moments. Source code of example is very short (80 lines) look at it after reading the entire article.

The method bindEvents add handlers for the event popstate, which is called when the user navigates through the history and allows the application to updateits state.

window.addEventListener('popstate', function(e){
  self.loadImage(e.state.path, e.state.note);
}, false);

The object event, which is passed to the event handler has a property state - the data that we have passed as first argument to pushState or replaceState.

We bind event handler click event on the DIV element, which is our filestructure. Using the delegation event, we open or close the folder or download a picture (with the addition of history record). We look at the className of the parent element in order to understand which of the items we clicked:

  • If this folder we open or close it
  • If this is a picture, then we show it, and add an element of history

   dir.addEventListener('click', function(e){
        e.preventDefault();
        var f = e.target;

        if (f.parentNode.classList.contains('folder')) {
          self.toggleFolders(f);
        }

        else if (f.parentNode.classList.contains('photo')){
          //be nice to FF 4 & 5, as they don't have .dataset yet
          //https://bugzilla.mozilla.org/show_bug.cgi?id=560112
          note = f.dataset ? f.dataset.note : f.getAttribute('data-note');

          self.loadImage(f.textContent, note);
          history.pushState({note: note, path:f.textContent}, '', f.href);
        }
   }, false);

A method that modifies the contents of pictures and updates its signature is very simple:

loadImage: function(path, note){
  img.src = path;
  h2.textContent = note;
}

I have a simple html5 history demo application that demonstrates the possibility of the updated interface of History object. We use pushState to add an element of history and event popstate to update page content.

In addition, when you click on the picture we get a valid URL in the address bar, so you can save or send it to someone.

# When can I use it?

Firefox 4+ Safari 5+ Chrome 10+ Opera 11.5+ iOS Safari 4.2+ Android 2.2+ IE ??? See browser list with History API supported

# Additional reading

See my post about HTML5 FileUpload API

1. Manipulating History for Fun & Profit 2. WHATWG HTML5 history API 3. W3C history API Spec 4. MDC Manipulating the browser history 5. History.js — emulates HTML5 history API(location.hash magic) in browser, which does not support it

rss_only