A modern replacement for the History API — intercept, manage, and navigate between SPA “pages” with a single event listener. Replaces pushState/popstate/hashchange boilerplate entirely.
navigation.addEventListener('navigate', ...)
to intercept all navigations in one place. Use e.intercept() to handle them as same-document
navigations, and navigation.navigate(url, { state }) to push new entries.
Built-in canGoBack/canGoForward and back()/forward()
replace the History API entirely.
window.navigation to function.
navigate event handlerClick the nav tabs to switch “pages”. Each click uses navigation.navigate() to push a URL, and a single navigate event handler switches the content panel. Check the browser URL bar — it updates without page reload.
Welcome to the SPA home page. Navigation is handled by a single navigate event listener — no router library needed.
This is the about page. The browser back/forward buttons work because the Navigation API manages history entries natively.
Contact page content. Each navigation creates a proper history entry with state — all via navigation.navigate().
navigation.updateCurrentEntry({ state })Type in the form fields. State is saved to the current navigation entry via updateCurrentEntry. Navigate away and come back — the state is restored from currentEntry.getState().
canGoBack / canGoForwardNative navigation controls using navigation.back(), navigation.forward(), and the canGoBack/canGoForward properties. Buttons auto-disable when navigation is not possible.
// Push state
history.pushState(state, '', url);
// Listen for back/forward
window.addEventListener('popstate', e => {
renderPage(e.state);
});
// Intercept link clicks
document.addEventListener('click', e => {
const link = e.target.closest('a');
if (!link) return;
if (link.origin !== location.origin)
return;
e.preventDefault();
history.pushState(
getState(link),
'',
link.href
);
renderPage(getState(link));
});
// No canGoBack/canGoForward
// No navigation entries list
// No intercept() for async
// hashchange needed separately
window.addEventListener(
'hashchange', handleHash
);
// One handler for everything
navigation.addEventListener(
'navigate', e => {
if (!e.canIntercept) return;
const url = new URL(e.destination.url);
e.intercept({
handler() {
renderPage(url);
}
});
}
);
// Built-in back/forward
navigation.back();
navigation.forward();
// Built-in state
navigation.canGoBack;
navigation.canGoForward;
navigation.currentEntry.getState();
navigation.entries();
// That's it. No hashchange.
// No link click interception.
// No popstate. One event.
<script>
// Feature detection
if (!window.navigation) {
alert('Navigation API not supported');
}
// Single navigate event handler
navigation.addEventListener('navigate', e => {
if (!e.canIntercept) return;
if (!e.destination.sameDocument) return;
const url = new URL(e.destination.url);
e.intercept({
handler() {
// Switch page content based on URL
showPage(url.hash.slice(2) || 'home');
}
});
});
// Programmatic navigation with state
navigation.navigate('#/about', {
state: { from: 'home' }
});
// Read state from current entry
const state = navigation.currentEntry.getState();
// Update state without navigation
navigation.updateCurrentEntry({
state: { ...state, newField: 'value' }
});
</script>