demo · v141
Route Interceptor
A four-route single-page app wired to the Navigation API's preCommitHandler. Toggle the interceptor on, pick a precommit action (auth check, data prefetch, or analytics), then navigate between routes. The timeline shows exactly when the navigate event fires, when precommit work runs, and when the URL finally commits — or aborts.
Navigation event details
Precommit timeline
the preCommitHandler pattern
navigation.addEventListener("navigate", (event) => {
if (!event.canIntercept) return;
if (new URL(event.destination.url).origin !== location.origin) return;
event.intercept({
// NEW in Chrome 141: preCommitHandler runs BEFORE the URL flips
async preCommitHandler({ commit }) {
log("precommit start");
// Auth check, data prefetch, analytics — all before commit:
await authCheck(); // throws to abort the navigation
const data = await prefetchData(event.destination.url);
commit(); // ← URL flips NOW; old page still visible until handler() runs
},
// handler() runs AFTER commit — swap the DOM here
async handler() {
renderNewRoute(location.search);
},
});
});
why this matters
Before preCommitHandler, intercept() committed immediately when the navigate event finished dispatching — the URL would flip before your async handler had fetched any data. This forced frameworks to show a loading skeleton on the new page while data loaded. With preCommitHandler, the URL stays on the old page (with the old scroll position and focus) until you call commit(), matching how browsers handle cross-document navigations internally. React Router's loader pattern and Remix's data-loading model now map naturally onto the Navigation API.