history.pushState({ id: 42 }, "", "/products/42");
render("/products/42");
window.addEventListener("popstate", (event) => {
render(location.pathname, event.state);
});
history.pushState changes the URL without a request, and the app draws the new view itself.
How it works: history.pushState(state, "", url) adds a new entry to the session history. It changes the URL in the address bar but makes no request. replaceState does the same, but replaces the current entry instead of adding one. The app then renders the matching view itself. This is what client-side routers do.
Back and forward: when the user presses back or forward, the browser fires popstate with that entry's state. The app re-renders for the new URL. pushState itself does not fire popstate. The new URL must be same-origin.
The server's part: the URLs are real paths, so the server must return the app's HTML for every route. This is a fallback to index.html. Without it, a refresh or a shared link on /products/42 returns a 404.
Routers must also handle scroll restoration, and move focus for accessibility.
pushStateandreplaceStatechange the URL without a request.popstatefires on back and forward, but not onpushState.- The new URL must be same-origin.
- The server must return the app's HTML for deep links.
- History API (MDN) (https://developer.mozilla.org/en-US/docs/Web/API/History_API)developer.mozilla.org