July 20, 2010 Jamie Appleseed
HTML5: Changing the browser-URL without refreshing page
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].
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
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
Looks like this feature was removed from the current spec, however.
Comment by wdh
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
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
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
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
Pingback: TempusFactor » Blog Archive » links for 2010-07-21
Thanks for using my photo in this blog post!
Comment by Aaron Nace
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
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
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
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
Thanks for your clean explanation!
Comment by Marçal Juan
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
@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 + 0x1337c0de
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
Hey guys, for a backwards compatibility History.js – https://github.com/balupton/History.js – gracefully degrades the HTML5 History/State API for HTML4 browsers while keeping support for data and titles as well as replaceState functionality. It also fixes a few browser incompatibilities with the API. Supports jQuery, MooTools and Prototype out of the box too
Comment by Benjamin Lupton
Pingback: 180+ HTML5 Tutorials and a Round-Up of HTML5 Round-Ups - WebsitesMadeRight.com
Pingback: 180+ HTML5 Tutorials and a Round-Up of Round-Ups - WebsitesMadeRight.com
Pingback: 270+ HTML5 Tutorials and a Round-Up of Round-Ups - WebsitesMadeRight.com
Useful resource that i was searching for it for 1 week :5 Grat work bro ! Thanks
Comment by Bari Rafik
Pingback: Cool feature of HTML5 | GUYA.NET
Pingback: Redes sociales y la adopción de los nuevos estandares. | Luis Carlos Cárdenas
Pingback: Cool feature of HTML5 « ARMATE THE TECHMATE
StackOverflow uses this new feature (it’s been implemented recently). I was doleful to implement it in my site, but now with large sites like SO using it, I’m completely happy.
Great article. Thanks.
Comment by Saeed Neamati
What a nice article!
Thank you very much.
It’s so useful for me.
Comment by 월풍
Here is an example demo to implement FACEBOOK like MENU navigation without refreshing the page but changing the url using HTML5 and get the content using AJAX
http://tinywall.info/demos/html5-history-api/menu1.php
Comment by Arun David
I will implement im my site in the future
http://www.equipebeta.com.br
thanks for this script
Comment by Renato Cassino
I am writing a “web app” for smartphones (iOS and Android) where I use JavaScript to create a finite state machine to deliver my app functionality. I also have the need to navigate to other HTML pages within my app. When navigation transitions back to the home page where the FSM resides, I need that page to be “as it were” without a page reload. Currently, the “webview” support in the smartphones causes a page reload. I definitely will explore this HTML5 pushState capability as a solution for my requirement. Thanks.
Comment by David
yay. found this by searching for “html5 url” on google.
just wanted to know how to do it for a private local hosted manga reader project.
Comment by GottZ
thanks for this script
i implement it in my site
http://astaza.com/
but there are better way to use ajax with jquery
http://benalman.com/projects/jquery-bbq-plugin/
thank you
Comment by العاب
Pingback: How can I change the page URL without refreshing the page? | Easy jQuery | Free Popular Tips Tricks Plugins API Javascript and Themes
Thank u, i was finding this way, by searchng this i have find out the gleam theme for wordpress used at this blog scienceinhand.com
Comment by Irfan korai
Here is an example demo to implement FACEBOOK like MENU navigation without refreshing the page but changing the url using HTML5 and get the content using AJAX
Comment by Imran Korai
AMAZING! Url change without a postback, I never thought it would be possible.
Comment by guideX