{"id":197129,"date":"2015-03-09T09:14:11","date_gmt":"2015-03-09T16:14:11","guid":{"rendered":"http:\/\/css-tricks.com\/?p=197129"},"modified":"2015-03-21T17:11:29","modified_gmt":"2015-03-22T00:11:29","slug":"using-the-html5-history-api","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-the-html5-history-api\/","title":{"rendered":"Using the HTML5 History API"},"content":{"rendered":"
The HTML5 History API gives developers the ability to modify a website’s URL without a full page refresh. This is particularly useful for loading portions of a page with JavaScript, such that the content is significantly different and warrants a new URL. <\/p>\n
Here’s an example. Let’s say a person navigates from the homepage of a site to the Help page. We’re loading the content of that Help page with Ajax. That user then heads off to the Products page which we again load and swap out content with Ajax. Then they want to share the URL. With the History API, we could have been changing the URL of the page right along with the user as they navigate, so the URL they see (and thus share or save) is relevant and correct.<\/p>\n
<\/p>\n
To check out the features of this API it’s as simple as heading into the Developer Tools and typing We’re interested in the The To fix this we’ll need to use the Now if we click on the back button we should find it working as we’d like it to, since This will throw an exception because the URL has to be of the same origin<\/strong> as the current one, otherwise we might risk major security flaws and give developers the ability to fool people into believing they were on a different website altogether.<\/p>\n Returning to those other parameters that are passed into this method, we can summarise them like this:<\/p>\n The most significant thing with these history API’s is that they don’t reload the page. In the past, the only way to change the URL was to change the This lead to the old hashbang method<\/a> of changing the URL without a full page refresh. Famously, Twitter used to do things this way and was largely criticized for it (a hash not being a “real” resource location).<\/p>\n Twitter moved aways from that, and was one of the early proponents of this API. In 2012 the team described their new approach<\/a>. Here they outline some of their problems when working at this kind of scale whilst also detailing how various browsers implement this specification.<\/p>\n Let’s build a demo!<\/a><\/p>\n In our imaginary interface we want the users of our website to find information about a character from Ghostbusters. When they select an image we need the text about that character to appear underneath and we also want to add a current class to each image so that it’s clear who’s been selected. Then when we click the back button the current class will jump to the previously selected character (and vice-versa for the forwards button) and of course we’ll need the content beneath to switch back again, too.<\/p>\n Here’s a working example<\/a> that we can dissect:<\/p>\n The markup for this example is simple enough: we have a Without any JavaScript this page will still function as it should, clicking a link heads to the right page and clicking the back button also works just as a user would expect it too. Yay for accessibility and graceful degradation!<\/p>\n Next we’ll hop on over to JavaScript where we can begin adding an event handler to each link inside the Inside this (Alternatively, we could also grab the link’s href attribute for this.)<\/p>\n I’ve replaced working code with comments so we can focus on the So at this point, clicking on an image will update the URL bar and the content with the Ajax request but clicking the back button won’t send us to the previous character we selected. What we need to do here is to make another Ajax request when the user clicks the back\/forwards button and then we’ll need to update the URL once again with We’ll first head back and update the state parameter of our This is the first parameter, Consequently we can then use this information however we like, which in this case is passing the name of the previous Ghostbuster we selected as a parameter into the Ajax If a user was to click on the picture of Ray our event listener would fire, which would then store the data attribute of our image within the What does this leave us with? Well, if we click on a character and then share the URL we’ve updated, then that HTML file would be loaded instead. It might be a less confusing experience and we’ll preserve the integrity of our URLs whilst giving our users a faster browsing experience over all.<\/p>\n It\u2019s important to acknowledge that the example above is simplistic since loading content in this way with jQuery is very messy and we\u2019d probably want to pass a more complex object into our If we were to use this technique on a larger scale then we should probably consider using a tool designed specifically for that purpose. For example pjax<\/a> is a jQuery plugin that speeds up the process of using Ajax and pushState simultaneously, although it only supports browsers that use the History API.<\/p>\n History JS<\/a> on the other hand supports older browsers with the old hash-fallback in the URLs.<\/p>\n I like thinking about URLs, and I particularly reference this post on URL design<\/a> by Kyle Neath all the time:<\/p>\n URLs are universal. They work in Firefox, Chrome, Safari, Internet Explorer, cURL, wget, your iPhone, Android and even written down on sticky notes. They are the one universal syntax of the web. Don’t take that for granted. Any regular semi-technical user of your site should be able to navigate 90% of your app based off memory of the URL structure. In order to achieve this, your URLs will need to be pragmatic.<\/p><\/blockquote>\n This means that regardless of any hacks or performance boosting tricks we might want to implement, web developers ought to cherish the URL and with the help of the HTML5 History API we can fix problems like the above example with just a little elbow grease.<\/p>\n The HTML5 History API gives developers the ability to modify a website’s URL without a full page refresh. This is particularly useful for loading portions of a page with JavaScript, such that the content is significantly different and warrants a new URL. Here’s an example. Let’s say a person navigates from the homepage of a […]<\/p>\n","protected":false},"author":223806,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":19795,"url":"https:\/\/css-tricks.com\/rethinking-dynamic-page-replacing-content\/","url_meta":{"origin":197129,"position":0},"title":"Rethinking Dynamic Page Replacing Content","date":"January 8, 2013","format":false,"excerpt":"Jesse Shawl takes an old(ish) CSS-Tricks demo and updates it for today's world. Using the HTML5 history API he changes the URL and content of a page when navigation items are clicked, without refreshing the page.","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":15167,"url":"https:\/\/css-tricks.com\/play-music-on-your-site-with-the-grooveshark-streaming-api\/","url_meta":{"origin":197129,"position":1},"title":"Play Music on Your Site with the Grooveshark Streaming API","date":"November 28, 2011","format":false,"excerpt":"Grooveshark is a web app for listening to music. You can search for any play just about any song there is. With an account you favorite stuff, build playlists, do social stuff, you know the drill. Perhaps less known is that Grooveshark has API's that allow you to play music\u2026","rel":"","context":"In "Advanced"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2011\/11\/groovediagram.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":240099,"url":"https:\/\/css-tricks.com\/loading-using-external-data-react\/","url_meta":{"origin":197129,"position":2},"title":"Loading and Using External Data in React","date":"April 1, 2016","format":false,"excerpt":"Hey JavaScripters! I\u2019ve been learning a bunch about React lately. It\u2019s very fun. It feels like a great way to write JavaScript. Seems to me it has almost the same feel jQuery did in the early days. Confession though: I\u2019m not master of it. I\u2019m about to show you how\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":16909,"url":"https:\/\/css-tricks.com\/using-ziptastic\/","url_meta":{"origin":197129,"position":3},"title":"Autofill City & State from Zip Code with Ziptastic","date":"May 3, 2012","format":false,"excerpt":"Most address fields on web forms ask for city, state, and zip code (or city and post code, outside of the US). But as us nerds often lament, city and state are redundant with zip code. Or at least they can be inferred from a correctly entered zip code. That's\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":17841,"url":"https:\/\/css-tricks.com\/web-audio-api-sound-on-hover\/","url_meta":{"origin":197129,"position":4},"title":"Play Sound on Hover – Web Audio API Edition","date":"August 31, 2012","format":false,"excerpt":"The Web Audio API is a totally different beast than HTML5 audio elements. It provides lower level access to the sound system allowing for higher precision sound output. Notary Sojac explains it and provides a simple framework to make working with it easier.","rel":"","context":"In "Advanced"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":235917,"url":"https:\/\/css-tricks.com\/better-font-events-with-the-native-font-loading-api\/","url_meta":{"origin":197129,"position":5},"title":"TypeKit Starts Using Native Font Loading API","date":"December 17, 2015","format":false,"excerpt":"Typekit has updated the WebFont Loader project with support for the new CSS font loading API: Before the introduction of the native API, we detected font loading by inserting test elements in the page. These elements were regularly polled for width to see if the font had loaded. This process\u2026","rel":"","context":"In "Link"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/197129"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/223806"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=197129"}],"version-history":[{"count":46,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/197129\/revisions"}],"predecessor-version":[{"id":198726,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/197129\/revisions\/198726"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=197129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=197129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=197129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}history<\/code> into the console. If the API is supported in your browser of choice then we’ll find a host of methods attached to this object:<\/p>\n
pushState<\/code> and
replaceState<\/code> methods in this tutorial. Returning to the console, we can experiment a little with the methods and see what happens to the URL when we use them. We’ll cover the other parameters in this function later, but for now all we need to use is the final parameter:<\/p>\n
history.replaceState(null, null, 'hello');<\/code><\/pre>\n
replaceState<\/code> method above switches out the URL in the address bar with ‘\/hello’ despite no assets being requested and the window remaining on the same page. Yet there is a problem here. Upon hitting the back button we’ll find that we don’t return to the URL of this article but instead we’ll go back<\/em> to whatever page we were on before. This is because
replaceState<\/code> does not manipulate the browser’s history, it simply replaces the current URL in the address bar.<\/p>\n
pushState<\/code> method instead:<\/p>\n
history.pushState(null, null, 'hello');<\/code><\/pre>\n
pushState<\/code> has changed our history to include whatever URL we just passed into it. This is interesting, but what happens if we try something a little devious and pretend that the current URL wasn’t css-tricks.com at all, but another website entirely?<\/p>\n
history.pushState(null, null, 'https:\/\/twitter.com\/hello');<\/code><\/pre>\n
history.pushState([data], [title], [url]);<\/code><\/pre>\n
\n
title<\/code> is the second parameter which can be a string, but at the time of writing, every browser simply ignores it.<\/li>\n
A Quick History<\/h3>\n
window.location<\/code> which always reloaded the page. Except, if all you changed was the
hash<\/code> (like how clicking a
<a href=\"#target\">link<\/a><\/code> doesn’t reload the page).<\/p>\n
An example using pushState and Ajax<\/h3>\n
.gallery<\/code> which contains some links and within each of them is an image. We then have the text beneath that we want to update with the selected name and the empty
.content<\/code> div that we want to replace with the data from each character’s respective HTML files:<\/p>\n
<div class=\"gallery\">\r\n <a href=\"\/peter.html\">\r\n <img src=\"bill.png\" alt=\"Peter\" class=\"peter\" data-name=\"peter\">\r\n <\/a>\r\n <a href=\"\/ray.html\">\r\n <img src=\"ray.png\" alt=\"Ray\" class=\"ray\" data-name=\"ray\">\r\n <\/a>\r\n <a href=\"\/egon.html\">\r\n <img src=\"egon.png\" alt=\"Egon\" class=\"egon\" data-name=\"egon\">\r\n <\/a>\r\n <a href=\"\/winston.html\">\r\n <img src=\"winston.png\" alt=\"Winston\" class=\"winston\" data-name=\"winston\">\r\n <\/a>\r\n<\/div>\r\n\r\n<p class=\"selected\">Ghostbusters<\/p>\r\n<p class=\"highlight\"><\/p>\r\n\r\n<div class=\"content\"><\/div><\/code><\/pre>\n
.gallery<\/code> element by using event propagation<\/a>, like so:<\/p>\n
var container = document.querySelector('.gallery');\r\n\r\ncontainer.addEventListener('click', function(e) {\r\n if (e.target != e.currentTarget) {\r\n e.preventDefault();\r\n \/\/ e.target is the image inside the link we just clicked.\r\n }\r\n e.stopPropagation();\r\n}, false);<\/code><\/pre>\n
if<\/code> statement we can then assign the
data-name<\/code> attribute of the image we select to the
data<\/code> variable. Then we’ll append “.html” to it and use that as the third parameter, the URL we’d like to load, in our
pushState<\/code> method (although in a real example we’d probably want to change the URL only after<\/em> the Ajax request has been successful):<\/p>\n
var data = e.target.getAttribute('data-name'),\r\n url = data + \".html\";\r\n history.pushState(null, null, url);\r\n \r\n \/\/ here we can fix the current classes\r\n \/\/ and update text with the data variable\r\n \/\/ and make an Ajax request for the .content element\r\n \/\/ finally we can manually update the document\u2019s title<\/code><\/pre>\n
pushState<\/code> method for now.<\/p>\n
pushState<\/code>.<\/p>\n
pushState<\/code> method in order to stash that information away:<\/p>\n
history.pushState(data, null, url);<\/code><\/pre>\n
data<\/code> in the method above. Now anything that\u2019s set to that variable will be accessible to us in a
popstate<\/a><\/code> event which fires whenever the user clicks on the forward or back buttons. <\/p>\n
window.addEventListener('popstate', function(e) {\r\n \/\/ e.state is equal to the data-attribute of the last image we clicked\r\n});<\/code><\/pre>\n
requestContent<\/code> function, which uses jQuery’s
load<\/code> method:<\/p>\n
function requestContent(file) {\r\n $('.content').load(file + ' .content');\r\n}\r\n\r\nwindow.addEventListener('popstate', function(e) {\r\n var character = e.state;\r\n\r\n if (character == null) {\r\n removeCurrentClass();\r\n textWrapper.innerHTML = \" \";\r\n content.innerHTML = \" \";\r\n document.title = defaultTitle;\r\n } else {\r\n updateText(character);\r\n requestContent(character + \".html\");\r\n addCurrentClass(character);\r\n document.title = \"Ghostbuster | \" + character;\r\n }\r\n});<\/code><\/pre>\n
pushState<\/code> event. Consequently this loads the
ray.html<\/code> file which will be called upon if the user selects another image and then clicks the back button. *Phew*.<\/p>\n
pushState<\/code> method but it shows us how we can immediately start learning how to use the History API. First we walk, then we run.<\/p>\n
The Next Step<\/h3>\n
Cool URLs<\/h3>\n
Common Gotchas<\/h3>\n
\n
href<\/code> attributes of an anchor element.<\/li>\n
return true<\/code> from Javascript click handlers when people middle or command click so that we don’t override them accidentally.<\/li>\n<\/ul>\n
Further Reading<\/h3>\n
\n
Browser support<\/h3>\n
\n\n
\n Chrome<\/span><\/th>\n Safari<\/span><\/th>\n Firefox<\/span><\/th>\n Opera<\/span><\/th>\n IE<\/span><\/th>\n Android<\/span><\/th>\n iOS<\/span><\/th>\n<\/tr>\n<\/thead>\n\n \n 31+<\/td>\n 7.1+<\/td>\n 34+<\/td>\n 11.50+<\/td>\n 10+<\/td>\n 4.3+<\/td>\n 7.1+<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"