References

Beginner-friendly references for web development, with live, editable examples.

The JavaScript history.pushState() method

Method JavaScript All modern browsers Updated
Quick answer

The history.pushState() method changes the URL shown in the address bar and adds a history entry, all without reloading the page. history.pushState(state, "", "/new-path"). It's the foundation of client-side routing in single-page apps. Listen for the popstate event to react when the user presses Back.

Overview

history.pushState() lets JavaScript update the URL without a full page load. It takes a state object (data you want associated with this history entry), a title argument (ignored by browsers — pass ""), and the new URL. The address bar updates and a new entry is added to the browser's history, but the page doesn't reload — your code is responsible for updating what's shown.

This is the engine behind client-side routing in single-page apps (React Router, Vue Router and friends all build on it). When the user clicks an in-app link, you prevent the default navigation, call pushState() to update the URL, and swap the content with JavaScript — giving real URLs and a working Back button without server round-trips.

The crucial partner is the popstate event: when the user presses Back or Forward, the browser fires popstate (with your saved state) so you can render the right view for the new URL. Note that pushState() itself does not fire popstate — only user navigation does. Its sibling replaceState() updates the current entry instead of adding a new one (useful for redirects or filter changes you don't want in history).

Syntax

history.pushState(state, "", url);

history.pushState({ page: 2 }, "", "/products?page=2");

// react to Back/Forward
window.addEventListener("popstate", (event) => {
  render(event.state);   // event.state is what you pushed
});

history.replaceState(state, "", url);  // replace, don't add

Parameters

The history.pushState() method accepts the following parameters.

Parameter Description
state A data object stored with the history entry (available later as event.state on popstate).
unused A title argument that browsers ignore — pass an empty string.
url The new URL to show. Must be the same origin as the current page.

Example

Live example
// minimal client-side routing
function navigate(url, state) {
  history.pushState(state, '', url);   // change URL, no reload
  render(state);
}

window.addEventListener('popstate', (e) => {
  render(e.state);   // user pressed Back/Forward
});

document.querySelector('a.nav').addEventListener('click', (e) => {
  e.preventDefault();
  navigate(e.target.href, { view: 'about' });
});

Best practices

  • Pair it with a popstate listener so Back/Forward render the right view.
  • Pass "" for the title argument — browsers ignore it.
  • Store what you need to re-render in the state object.
  • Use replaceState() for changes that shouldn't add a new history entry (redirects, filter tweaks).

Frequently asked questions

How do I change the URL without reloading the page?
Use history.pushState(state, "", "/new-url"). It updates the address bar and adds a history entry with no reload.
How do I handle the Back button with pushState?
Listen for the popstate event on window — it fires on Back/Forward and gives you the saved state to re-render.
What is the difference between pushState() and replaceState()?
pushState() adds a new history entry; replaceState() modifies the current one without adding to history.
Does pushState() trigger popstate?
No. Only user navigation (Back/Forward) fires popstate. After pushState() you update the view yourself.