The History Interface

Hey ,

I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.

Please upgrade (use this link) access this content.

I'm super eager to help you learn more!

The History Interface

History does two things. It lets you:

  • Navigate to a specific page in the browser history
  • Change the URL without a page refresh

You can use the following methods to navigate the history stack.

  • history.back – goes backward one page
  • history.forward – goes forward one page
  • history.go – goes to a specific page
history.back() // Goes back 1 page
history.forward() // Goes forward one page

history.go lets you navigate to a specific page in the browser history. It takes in an integer to determine which page to go.

  • Negative numbers indicate the number of pages to go back.
  • Positive numbers indicate the number of pages to go forward.
  • 0 reloads the current page
history.go(-1) // Go back one page
history.go(2) // Go forward 2 pages
history.go(0) // Reloads the page

If you pass in a value that’s out-of-bounds, history.go will fail silently and do nothing. An out-of-bounds value means the browser couldn’t find a page at the value you passed in.

Changing URL with History

You can change the URL with history.pushState and history.replaceState.

  • pushState adds a new entry into the browser history
  • replaceState overwrites the current entry in the browser history.

Both pushState and replaceState has the same syntax.

history.pushState(state, title, url)
history.replaceState(state, title, url)
  • state let’s you define an object which you can retrieve on a popstate event. (More on popstate later).
  • title is the title of the page to navigate to.
  • url is the URL you want to navigate to.

Here’s an example where we have a button that changes the path from / to /hello.

const button = document.querySelector('button')

button.addEventListener('click', _ => {
  history.pushState({ value: 'hello world' }, 'Hello', '/hello')
})

Most browsers don’t respect the title attribute at the time of writing (February 2021), so we need still need to set the title with document.title.

The code looks like this:

history.pushState(state, title, url)
document.title = title

Note: Chrome is a little weird. If you place document.title after history.pushState, the document title will only update after 1 second. This doesn’t happen on Safari and Firefox — document title gets updated immediately. I’d say it’s an inconsequential problem so we don’t have to worry too much about the order.

Popstate

The popstate event fires when the history is used to move the user forward or backwards to a page. There are two possible ways for this to happen

  • The user clicks on the back or forward button
  • We use history.back, history.forward or history.go.

If you added a state object with history.pushState or history.replaceState, you can retrieve the object with the popstate event.

  • replaceState adds the state object to the current page
  • pushState adds the state object to the page you’re navigating to.

Here’s an example. When a user clicks a button, we replace the current location with history.replaceState first. Then, we change the location with history.pushState.

const button = document.querySelector('button')

button.addEventListener('click', _ => {
  history.replaceState({value: 'First Page'}, '', '/hello')
  history.pushState({value: 'Second Page'}, '', '/second')
})

We can retrieve this state object in a popstate event.

window.addEventListener('popstate', event => {
  console.log(event.state)
})

When you navigate back to the first page via history, you’ll see First Page. When you navigate back to the second page via history, you’ll see Second Page.

Real world use-case for the state object?

The popstate event doesn’t occur when users navigate to the page with an URL. Since the popstate event doesn’t occur, we cannot reliably use the state object for any critical information on that page.

Twitter wrote about how they used the state object in an article in 2012 — that’s many years ago, so I’m not sure whether it’s still current.

History and Servers

Try loading a page with the URL changed by history. You will most likely reach a page-not-found error. (A simple way to test this is refresh the page after a pushState)

This means we need to use a custom server that’s able to manage these “historied” URLs. Otherwise, people navigating to our sites will reach pages that cannot be found.