How does this work(URL bar change without page load)?

Hi there everyone!

To explain what I’m asking about, when I go to certain sites(Amazon, for instance), choosing certain elements on the page will alter the URL in the location bar. In this case, it allows you to pick a size and color for a shirt being sold and sharing that url would take a person to that shirt with those options already selected.

How does this happen? I’ve forced a page load with form options but when I see this, it seems that the page isn’t loading, it just immediately changes the URL.

I’ve googled but I don’t even know what to call it so I’m coming up with nil. Any insight would be most appreciated. Thanks for your time!

Hi @schwim, it’s the history API you’re looking for:

Specifically, have a look at pushState() / replaceState() to update the URL in the address bar.

2 Likes

That’s fantastic, thanks so much!

I am reading that the portion of the function that changes the page title doesn’t work. Is that true? I’ve found three SE topics discussing this and when I tested it, my browser page title didn’t change either.

  <script type="text/javascript">
    window.history.replaceState({}, "New Title", "/?action=default");
  </script>
1 Like

the second parameter for replaceState is unused, and is present only for backward compatability [MDN].

Glad I could help. :-) Yes as mentioned the second parameter is ignored. However you can always set the document title manually like so:

document.title = 'New Title'

And in order to keep the title updated when the user navigates the history (e.g. by clicking the browser back button), you might include the title in the history state object and listen to popstate events:

HTML

<nav>
  <a href="/foo" title="Foo Title">foo</a>
  <a href="/bar" title="Bar Title">bar</a>
</nav>

JS

const originalTitle = document.title

document.querySelectorAll('nav a').forEach(link => {
  link.addEventListener('click', event => {
    event.preventDefault()

    document.title = link.title
    // Push a state object with the current title
    window.history.pushState({ title: link.title }, '', link.href)
  })
})

window.addEventListener('popstate', event => {
  // Set the title from the previous history state if available
  document.title = event.state?.title || originalTitle
})
1 Like