What are the differences between history.pushState & location.hash?

35,878

Solution 1

location.hash has a better support than the history.pushState method.

The advantage of the pushState method is that you can bind a state to the history entry.

If you don't need this state object, I recommend to use the location.hash property, to have better compatibility with older browsers.

location.hash = 'new-hash';
console.log(history.state); // null or undefined

history.pushState({extraData: "some state info"}, '', 'new-hash'); //<---
console.log(history.state); // [object Object] = {"extraData": "some state info"}

Solution 2

Pushstate is the future. It's better because:

  1. It looks cleaner.
  2. On revisit of a deep link you can actually surface real serverside data to support things like SEO and Facebook Open Graph (both send spiders to scrape the html of your page).
  3. Servers don't have access to hash tags data so you don't see it in your server logs so it helps some with analytics.
  4. It helps fix hash tag issues. For example I had an Nginx rewrite to redirect users visiting my app to the same https url. It works in all browsers but Safari which will redirect you to just the domain without the hash (so annoying)!
  5. You can actually use hash tag for what is was meant for, deep linking to sections of long pages.
  6. You can fallback to using real HTTP backend requests for browser that don't support push state OR you can fallback to using hash tag. Both require extra implementation but are easily doable with a little work.

See this talk from Github designer for more: http://warpspire.com/talks/responsive/

Solution 3

This is a rather old question (5 years+ at the time of this reply) but a lot of comments on existing replies are asking for an update based on the "current" state of things.

Here's the deal:

HTML5's pushState is supported on all major browsers. If you are supporting older browsers too, history.js provides a great polyfill that lets you use pushState natively and have it easily fall back to legacy URLs for older browsers. Now that pushState is natively supported does not mean, however, that it is definitively the way to go.

There is a very important point that was not raised in any of the older answers and that is that hash URLs and pushState URLs are not only different in the way they appear, but they are actually different in the way they work, too. This fundamental difference between the two might lead you to choose one over the other.

pushState is prettier and cleaner and can be used to completely fake navigation on your site/in your app. For example, GitHub uses it to replace all navigation invisibly. When you click any link on their site, javascript is used to intercept that click and turn it into an AJAX request that updates the contents of the page without loading a new page, while the URL in the location bar changes to match the content that was fetched. This is what pushState was meant to be used for.

In GitHub's case, http://mysite/page1 and http://mysite/page2 are both valid URLs. They are "real" links with "real" content, and initially visiting either page goes through the traditional MVC approach. GitHub uses pushState for navigation in modern browsers, but does not require it - i.e. pushState is used as a "feature add" to (in their opinion) lead to a better user experience when it comes to navigation. When you copy the link in the browser address bar, you are copying a link that was formed via javascript & pushState, but a link that is nevertheless real and valid.

However, if you are starting from scratching and creating a single page app and are not using an MVC framework, chances are that you actually only have a single page, especially if you are not using a dynamic backend (i.e. content is all retrieved via javascript, never generated by a server). In this case, if you use pushState over hash urls, you will need to handle the case that the URL in the browser is not the real URL. I will illustrate.

The user loads your single page app: http://mysite/mainpage

At this point, the browser bar contains the real link to your app, and will take the user to the same view they currently see: the main page. Now they click a link that will take them to a "page" showing the details of some activity. At this point, you want to update the location bar to indicate the change in state. You either use a hash URL and your location bar looks like http://mysite/mainpage#charts/1 or you use pushState and trick it to becoming http://mysite/mainpage/charts/1

If you used pushState, that is not a real link. Navigating via the browser's back/forward buttons will work great and the user will go from the main page to the detail page in both the location bar and in the app (presuming you handle the state change correctly), but if the user bookmarks this link or copies and pastes the link to share it, additional server-side voodoo will be required.

You will need to redirect requests to /mainpage/charts/1 to /mainpage and then use JS to resolve the actual URL and carry out the intended state change operation. A server redirect is absolutely required. You cannot host this page on AWS or on your local disk without a scriptable http server.

Now if you used hash urls, your URL that the user would have seen and interacted with would have been http://mysite/mainpage#/charts/1 and that is a valid, real url. Browsers understand that there is just one page, and whether the user copies and pastes the link or bookmarks it, you just have to handle the hash state in javascript and do not need any server-side magic to make things work.

What no one seems to mention is that pushState and hash links are not mutually exclusive. pushState is just an API to manipulate the browser location that is visible to the user and implement reliable back/forward navigation in modern browsers. It says nothing about what your URL scheme should look like.

In 2017, Google and just about every other JS-capable bot understand hash URLs and traverse them just fine. Google wants you to use the #! abomination for SEO maximization purposes, but even if you don't, your site will be navigable just fine.

The correct answer is to use whatever fits your needs best. If you have real URLs and want to fake navigation between them, use pushState and carry on (optionally with a polyfill for older browsers). But if you have a single-page app, don't pretend not to (unless you have a very good reason). Use hash URLs to make your life easier and not introduce unnecessary problems and then use pushState to manipulate those hash URLs to take advantage of better back/forward support.

Solution 4

history.pushState is better than location.hash. but it is a HTML5 feature. so always better to have a fallback method like below.

if (typeof(window.history.pushState) == 'function') {
    window.history.pushState(null, path, path);
} else {
    window.location.hash = '#!' + path;
}

Solution 5

I agree with the other answers, but here are a few arguments in favor of location.hash:

  • it works in every browser, including Internet ExploderTM
  • history.pushState is a developing standard, and the API may change in the future
  • if the users opens a link in a new window/tab, a hash-URL makes sure there is no server request needed to load the page (if the correct caching headers are set)
  • The server configuration is easy, since all the server ever sees is the URL without hash-part

edit: I forgot one

  • with hashtags, you can use real links (a href). So you don't have to set up click listeners, which improves performance and reduces code size.
Share:
35,878
Krueger
Author by

Krueger

Updated on August 13, 2022

Comments

  • Krueger
    Krueger almost 2 years

    I want to update the URL using window.location.hash or history.pushState.

    What are the differences and advantages of each method?

  • Ansel Halliburton
    Ansel Halliburton almost 12 years
    good answer, but I don't quite agree with the SEO part. You can use hash-urls and still have your page indexed. See developers.google.com/webmasters/ajax-crawling
  • Robert
    Robert almost 12 years
    But is it possible to bookmark a history.state or to post it on facebook? I think it's possible with hashes. They're completely different things.
  • Tracker1
    Tracker1 almost 12 years
    Google will send #! based hashes... which requires a bit of effort... did this for photogallery.classiccars.com
  • Rob W
    Rob W almost 12 years
    @Robert When you bookmark something, the URL as currently seen in the browser is used. The state object is associated with a history entry. And such, it is only available when one navigates to the page by browsing the history (and e.g. session restore after a browser shutdown). One method does not exclude the other one: It's legal to use history.pushState('some long state cached from server', '', '/posts/id#prefix-some-specific-identifier'), for example, if the application really requires it. In this example, a server response is cached. The hash could also have been a slash, by the way.
  • Robert
    Robert almost 12 years
    Ah, of course. So your answer really boils it down. hash has better support while pushState is more powerful.
  • Hello World
    Hello World almost 10 years
    Pushstate has a slight disadvantage though: It forces the server to render the page for you upon the first visit / when you open a link page in a new tab. If a person is opening 10s of tabs (Say, browsing a Gallery and opening interesting pictures), it's considerably slower than hashbangs because ajax is not used at all.
  • Mauvis Ledford
    Mauvis Ledford almost 10 years
    @Hello-World: That is an assumption. For many/most JavaScript-based frameworks it's doing the exact same thing that hashbangs would have.
  • Hello World
    Hello World almost 10 years
    Can you please explain? suppose I visit example.com/ajax#gallery , my browser downloads some js through example.com/ajax and then that js requests and renders #gallery. When I open example.com/ajax#image1 in a new tab, my browser has already cached example.com/ajax so it only needs to fetch #image1 and render it. As far as I can see, this is not the case with Pushstate. When you open example.com/ajax/image1 (pushstate) in a new tab or visit it for the first time, the browser has to download a full page regardless of the cache at example.com/ajax. If I'm wrong, I'm open for correction.
  • Mauvis Ledford
    Mauvis Ledford almost 10 years
    @Hello World: Ok you are technically right. Generally when pushstate is being used it changes the URL dynamically and no extra page load is done. If you right click and open a link in tabs you are not really utilizing the whole point of dynamic pushstating. Click an image in your Facebook stream, note the dynamic URL change, and then paste the URL in a new window. What you just saw is way more advantageous than the "disadvantage" you mention. In this case it's actually a bonus not a disadvantage.
  • Hello World
    Hello World almost 10 years
    Are there any plans to make Pushstate better with new tabs?
  • Hello World
    Hello World almost 10 years
    (Context: In Facebook, the gallery is ajax based, clicking a photo changes the URL and enlarges that photo, copying the URL to a new tab loads a static page of the photo). This is not more advantageous. Consider this alternative: Gallery is at fb.com/#gallery-17 . Clicking a photo enlarges the photo and changes url to fb.com/#photo-521. That is far more efficient when opening multiple photos because fb.com is always cached.
  • Hello World
    Hello World almost 10 years
    Also, opening fb.com/#photo-521 for the first time/in a new tab would just load that photo without any regard to the gallery.
  • Mauvis Ledford
    Mauvis Ledford almost 10 years
    fb.com/#gallery-17 is a hack and doesn't support SEO (web servers can't even see the hash tag in the server logs). fb.com/gallery-17 is a legitimate address for a resource item. If a user goes to fb.com/galleries/#gallery-17 depending on how its architected the user could be fetching more content than was necessary (list of galleries). Hashtag hack can be just as "wasteful" as pushstate. CURL, WGET, and other tools can't even fetch hashtag specific resources. Hash tag was meant to scroll down the page to a resource. It was never meant for the hacky stuff we are now growing out of.
  • Mauvis Ledford
    Mauvis Ledford almost 10 years
    Additionally fb.com/#gallery-17 is slower than fb.com/gallery-17 as the whole page and its content needs to load then an ajax call needs to be made and loaded in to the page for the right content - as apposed to just showing the right content. Pushstate is the future because in the case of FB stream you popup a picture and keep your context behind it but if you want to bookmark that URL you go directly to the resource that you bookmarked. If you saved a hashstated URL then it loads content you don't need before the resource you want loads. Think about it. Leaving the discussion now.
  • Hello World
    Hello World almost 10 years
    SEO can be supported with hashbangs. fb.com/#gallery-17 is slower indeed, but new tabs with hash/hasbangs are faster. Regarding CURL and WGET, that's totally true. I am not saying hashbangs are a holy grail, I only stated an advantage.
  • Hello World
    Hello World almost 10 years
    I made a relevant question here: webmasters.stackexchange.com/questions/65694/…
  • hous
    hous over 8 years
    After 3 years since this question , which one is better now , pushstate or location.hash ?
  • hous
    hous over 8 years
    After 3 years since this question , which one is better now , pushstate or location.hash ?
  • Rob W
    Rob W over 8 years
    @hous history.pushState or history.replaceState and using history.state if you truly need to associate data with the history entry. If you want the page state to be bookmarkable, then location.hash is sufficient (because a bookmark can only store the page URL, not the history state).
  • hous
    hous over 8 years
    @Rob W , I'd like to create ajax form search and displaying results without reload page and it will be an ajax pagination also , wich one choose ? Thanks
  • Rob W
    Rob W over 8 years
    @hous location.hash suffices.
  • Nicolas Le Thierry d'Ennequin
    Nicolas Le Thierry d'Ennequin about 8 years
    Suppose I have a single-page application with no dynamic backend (basically, the app is just a static index.html file plus the JS machinery). If I understand well, I can't use pushState in this situation because the server is unable to respond to the URLs that describe the application state. In that situation, I'm obliged to use location hash. Am I understanding correctly?
  • Pascal
    Pascal almost 8 years
    Your user experience is determined by a # which most users do not even notice?
  • Fabio Lolli
    Fabio Lolli over 6 years
    I'm not sure what you mean with the last sentence: are you suggesting to replace URL with location.hash and then do it again with pushState? How would that help? From what I understand the main issue with pushState is bookmarking, but if we were to do this wouldn't we end up with bookmarked URL that requires redirection magic anyway? BTW, extremely clear and informative, trying to get all this info felt like composing a difficult puzzle, and here you really touched almost everything related to the discussion, thanks
  • ijmacd
    ijmacd over 6 years
    @FabioLolli in regards to the last sentence - In my apps I sometimes find myself manipulating the location hash via pushState and replaceState. For example a recent app performed searching on keypress. This searching should update the URL for bookmarking/forwarding etc. but you wouldn't want each keystroke to fill up the history stack with a new entry (as would happen by just manipulating location.hash). Instead I use replaceState while typing then after some debounce timeout or hitting the enter key do a pushState if necessary.
  • javajosh
    javajosh over 6 years
    Actually, as of Oct. 2015 Google does NOT want you to use #!. webmasters.googleblog.com/2015/10/…
  • mindplay.dk
    mindplay.dk about 5 years
    A fallback makes no sense here: location.hash will work just as well on browsers that also support pushState - and if you actually needed pushState (because you needed to store an object) then location.hash wouldn’t work as a fallback. Just pick one.