BLOG

July 20, 2010  /  Jamie Appleseed  /  Tech 

An often overlooked feature of HTML5 is the new “onpopstate” event.

This new feature offers you a way to change the URL displayed in the browser* through javascript without reloading the page. It will also create a back-button event and you even have a state object you can interact with.

This means you won’t have to use the hash-hack anymore if you want add state to your AJAX-application, and search engines will be able to index your pages too.

So how does it work? Well, it’s fairly simple. In Chrome you write:

window.history.pushState(“object or string”, “Title”, “/new-url”);

Executing this line of code will change the URL to my-domain.com/new-url (3rd option). The “Title” string (2nd option) is intended to describe the new state, and will not change the title of the document as one might otherwise expect. The W3 documentation states:

“Titles associated with session history entries need not have any relation with the current title of the Document. The title of a session history entry is intended to explain the state of the document at that point, so that the user can navigate the document’s history.”

So if you want the document’s title to change to match the title of the history entry, you’ll need to write a hook for that (hint: just tie a function to the onpopstate event). Finally, “object or string” (1st option) is a way to pass an object to the state which you can then use to manipulate the page.

You can programmatically invoke the back-function by running:

window.history.back();

And you can of course go forward too:

window.history.forward();

Or even go to a specific history state:

window.history.go(2);

The object you pass as the first option to the pushState function will stay with each state, so if you go back in the history, you’ll get the object for that state. If you need to manipulate a state (instead of creating a new one) you can use:

window.history.replaceState(“object or string”, “Title”, “/another-new-url”);

Note that while this will change the URL of the page, it will not allow the user to click the back-button to go back to the previous state because you’re replacing the current state, not adding a new one. So, this is the correct behaviour.

Personally, I think the URL should be the first parameter and then the two other options should be optional. Regardless, this feature will certainly come in handy when working with AJAX- and Flash-applications that need state (read: bookmarkable pages and back-button support). Anyone looking to make their Flash- or AJAX-application indexable by search engines so they will get better raking in Google and the likes, should also have a look at this new feature.

The most prominent implementation of this HTML5-feature that I’ve seen is in the new Flickr layout. Here’s an example page (remember to enable the new layout if you haven’t already). Now, if you’re using the latest version of Chrome or Safari and click one of the sets, e.g. “Strobist”, it will slide open and the URL will change but you’ll notice that the page doesn’t reload.

It’s worth noting that Flickr uses replaceState instead of pushState – in other words, they don’t add a back-button event. I’m guessing they feel that switching back and forth between opened/closed sets is too small a change for a back-button event (I’d certainly agree with them on that decision), so instead they just replace the URL so if you copy/paste the link to a friend, they’ll see the exact same page that you did.

Another interesting thing is how Flickr still use the old hash-hack as a fallback if you’re running on browsers that don’t support this new HTML5-feature. I predict/hope that a lot of the plugins that help you easily implement the hash-hack will bake this into their core so people with new browsers can start reaping the benefits.

The latest versions of Chrome and Safari already have support for “onpopstate” and Firefox 4 will have support for it as well. Unfortunately, it seems like IE9 won’t be supporting this feature if we are to believe this Wikipedia article (”Trident” is IE’s layout engine).

Check out the W3 specification for more info.

* For security reasons, you can only change the path of the URL, not the domain itself. So you can change anything in the URL after my-domain.com/[change-the-stuff-here.html].

16 Comments »

  1. Since window is the global “context” object, everything that is a property of window is accessible without spelling ‘window.’ out in browser JavaScript. So it makes no difference whether you write ‘history’ or ‘window.history’, both will access ‘window.history’ (unless you have a local variable history shadowing the global, of course).

    Comment by moeffju — July 21st, 2010 @ 02:25

  2. Great writeup for a long overdue feature. I hope that IE9 might still include it after all, but anyway, off to try it out.

    Comment by Ilia — July 21st, 2010 @ 12:12

  3. Looks like this feature was removed from the current spec, however.

    Comment by wdh — July 21st, 2010 @ 17:57

  4. Ah hell, I don’t know yet, but a quick search didn’t find it. Was definitely not a thorough search, however.

    Comment by wdh — July 21st, 2010 @ 17:58

  5. There’s no such thing as accessor for window properties. In JS window is the global object. All global variables are window properties (alert() === window.alert()).

    Comment by kl — July 21st, 2010 @ 18:00

  6. This is neat, good it’s supported in HTML5. It was pain to handle these ourselves.

    Sad to hear about IE, not sure why M$ doesn’t always comply with standards?

    Thanks

    -abdul

    Comment by Abdul Qabiz — July 21st, 2010 @ 21:03

  7. Ahoy, thanks for noticing this. I’m the one at Flickr who implemented this stuff.

    Deciding when to use pushState and when to use replaceState can get a little subjective. We’re basically making our best guess at which interactions a user would expect a back button to undo. So, we use pushState for opening and closing the lightbox and navigating to another photo in the lightbox. But we use replaceState for paginating comments and changing contexts (as you mentioned for sets).

    Comment by Trevor — July 21st, 2010 @ 22:48

  8. [...] Spoiled Milk ApS > Blog » HTML5: Changing the browser-URL without refreshing page (tags: html5 ajax) [...]

    Pingback by TempusFactor » Blog Archive » links for 2010-07-21 — July 22nd, 2010 @ 03:06

  9. Thanks for using my photo in this blog post!

    Comment by Aaron Nace — July 22nd, 2010 @ 07:44

  10. Really informative, thanks!
    I saw that Flickr behavior and was wondering how it was working… I even thought it could be a Chrome’s bug!

    This here will change the face of the web. And it might create bad ideas, too. Like client side Javascript URL rewriting (looks dumb but I’m sure some folks/clients will want that)…

    Comment by Quentin — July 22nd, 2010 @ 11:06

  11. Couldn’t this be abused by filling up the history with spam sites – sort of like how redirect can seem to lock you into a site by refusing to go back in history?

    Comment by Wouter Van Hemel — July 22nd, 2010 @ 13:56

  12. I now use it on my company website : http://studio87.fr with a # fallback for browsers that don’t support it

    Thanks for that great article !

    Comment by riper — July 22nd, 2010 @ 14:25

  13. Oh good, now we’re going to have annoying things like this used to be

    http://www.javascriptkit.com/script/cutindex19.shtml

    Comment by 0x1337c0de — July 22nd, 2010 @ 15:36

  14. Thanks for your clean explanation!

    Comment by Marçal Juan — July 22nd, 2010 @ 20:19

  15. Thanks for the pointers to the APIs. I’ve started a project to port the API to browsers that don’t support it:

    http://github.com/fortes/history.js

    Patches welcome! :)

    Comment by fortes — July 22nd, 2010 @ 23:05

  16. @moeffju + kl
    Thanks, I’ve removed the inaccurate note.

    @Trevor
    Great job on implementing this! I think you hit just the right balance in deciding when to use pushState and when to use replaceState.

    @Aaron Nace
    Thank *you* for some brilliant photography!

    @Quentin + Wouter Van Hemel + 0×1337c0de
    Like so many other javascript features, this can be abused. However, I don’t think we can limit useful innovation because some may abuse it. While not having the “Back button” work is annoying, it’s not a major security threat or anything.

    @riper
    Well done. This is exactly the kind of use we’ll be seeing more of in the next months. Use pushState for browsers that support it and having the good ‘ol hash tag hack for IE.

    @fortes
    Interesting project – good luck with it!

    Comment by Jamie Appleseed — August 2nd, 2010 @ 18:20

RSS feed for comments on this post. TrackBack URL

LEAVE A COMMENT


COPENHAGEN
Spoiled Milk ApS
Nørrebrogade 32, 2.
DK-2200 Copenhagen
Denmark


+45 32 10 05 33
ZURICH
Spoiled Milk Zweign.
Hammerstrasse 11
CH-8008 Zurich
Switzerland


+41 44 586 99 05
SUBSCRIBE TO NEWSLETTER