👀 Live Preview
Push a route, then use your browser Back button — popstate updates the label:
Route: home — click a button, then Back

The onpopstate attribute is an inline event handler for the popstate event on the window. It runs when the user moves through session history with the Back or Forward button — typically after you have used history.pushState() or history.replaceState() to build client-side routes. Read event.state to know which “page” to show. Put onpopstate on <body> or use window.addEventListener("popstate", …). It does not fire on initial load and does not fire when you call pushState itself.
Inline JS.
Back / Forward.
Global scope.
Route data.
SPA routing.
History API.
onpopstate AttributeThe primary purpose of onpopstate is to respond when the active history entry changes — so your app can update the UI when the user clicks Back or Forward instead of reloading from the server. Single-page applications (SPAs) push new URLs with history.pushState() and listen for popstate to swap views.
The popstate event fires on the window object. The handler receives an event whose state property holds the object you passed to pushState or replaceState for the current entry (or null for normal navigations).
Call pushState when the user navigates in-app; handle popstate when they use Back/Forward. Together they power History API routing.
Set onpopstate on body or assign window.onpopstate in JavaScript:
<body onpopstate="handlePopState(event)">
…
</body>
<script>
window.onpopstate = handlePopState;
window.addEventListener("popstate", handlePopState);
</script>popstate event fires on the window.<body> as a window event content attribute.window.onpopstate in script.pushState or replaceState — only on Back/Forward navigation.addEventListener to read event.state reliably.replaceState on first load so Back works predictably.The onpopstate attribute accepts a string of JavaScript code:
onpopstate="handlePopState(event)" — Call a named function with the event.onpopstate="renderFromState(event.state)" — Update UI from stored route data.window.onpopstate = (event) => { … } — property assignment.function handlePopState(event) {
var route = event.state ? event.state.route : "home";
document.getElementById("view").textContent = "Showing: " + route;
document.title = route.charAt(0).toUpperCase() + route.slice(1);
}
window.addEventListener("popstate", handlePopState);| Property / API | When it runs | Notes |
|---|---|---|
popstate | Back / Forward in session history | onpopstate |
event.state | On popstate | From pushState / replaceState |
pushState() | When you call it | Does not fire popstate |
replaceState() | When you call it | Replaces current entry |
hashchange | URL hash (#) changes | Hash-based routing |
| Handler attribute | onpopstate on body | Window event handler |
| Target | Supported? | Notes |
|---|---|---|
<body> | Yes | Window event on body (HTML) |
window | Yes | Primary target in JavaScript |
<div>, <button> | No | Use window listeners |
<a href> normal click | N/A | Full navigation — not popstate |
history.back() | Related | Triggers popstate |
onpopstate vs hashchange vs onpageshow| API | When it fires | Typical use |
|---|---|---|
onpopstate | Session history Back/Forward | SPA routes with pushState |
onhashchange | URL fragment changes | Hash-based SPA routing |
onpageshow | Page becomes visible | bfcache restore, refresh data |
pushState() | When you call it | Add history without reload |
Inline body handler, dynamic window.onpopstate, and a mini SPA router using event.state.
Push a route, then use your browser Back button — popstate updates the label:
Route: home — click a button, then Back
Handle Back/Forward after pushing history entries:
<body onpopstate="popStateHandler(event)">
<button onclick="goTo('about')">About</button>
<p id="status"></p>
</body>
<script>
history.replaceState({ page: "home" }, "", "/home");
function goTo(page) {
history.pushState({ page: page }, "", "/" + page);
}
function popStateHandler(event) {
var page = event.state ? event.state.page : "home";
document.getElementById("status").textContent =
"popstate — now on: " + page;
}
</script>pushState adds entries to session history. When the user clicks Back, the browser fires popstate and the body attribute runs popStateHandler(event).
Assign the handler on window at runtime:
<script>
history.replaceState({ page: "Home" }, "", location.pathname);
window.onpopstate = function (event) {
var label = event.state ? event.state.page : "(no state)";
document.getElementById("log").textContent =
"popstate — event.state.page: " + label;
};
</script>Assigning window.onpopstate is equivalent to the inline body attribute for the popstate event. Seed the first entry with replaceState so Back has somewhere to go.
Intercept link clicks with pushState; restore the view on popstate:
nav.addEventListener("click", function (event) {
var link = event.target.closest("a[data-route]");
if (!link) return;
event.preventDefault();
var route = link.dataset.route;
history.pushState({ route: route }, "", "/" + route);
render(route);
});
window.addEventListener("popstate", function (event) {
var route = event.state ? event.state.route : "home";
render(route);
});pushState updates the URL without reloading. popstate keeps the UI in sync when the user uses browser history controls — the core pattern behind History API SPAs.
document.title on route change so screen reader users know the page context changed.aria-live="polite" on a status region when content swaps via popstate.<a href> with preventDefault + pushState so middle-click and copy-link still work.Click, pushState.
History changes.
onpopstate runs.
Read event.state.
The popstate event, onpopstate handler, and History API (pushState / replaceState) are supported in all modern browsers.
onpopstate supportAll major browsers fire popstate when session history changes.
Bottom line: Reliable for History API routing in all modern browsers.
pushState with popstate listenersreplaceState on loadevent.state to restore the correct viewaddEventListener("popstate", …) in productiondocument.title on each route changepushStatealert() on every popstateonpopstate on random divs — use windowThe onpopstate attribute runs JavaScript when the user navigates session history with Back or Forward — essential for single-page apps built on the History API.
Combine it with history.pushState(), read event.state with addEventListener, and seed the initial entry with replaceState so routing behaves predictably from the first visit.
onpopstateBookmark these before wiring History API routing.
Global.
ScopePair both.
PatternRoute data.
APIWhen it fires.
TriggerInitial skip.
Gotchapopstate event fires — when the user navigates session history with Back or Forward after entries were created with the History API.pushState and replaceState do not trigger popstate. Popstate fires later when the user moves through that history.pushState or replaceState for the active entry. It is null for entries from normal full-page navigations.history.pushState() from a button click, then click the browser Back button. Your popstate handler should run and event.state should hold your data.window.addEventListener("popstate", handler) is preferred in production — you need it to read event.state and can attach multiple listeners.Practice the onpopstate attribute with pushState and SPA examples in the Try It editor.
5 people found this page helpful