v146 · Web APIs · Navigation API

Navigation API: post-commit handler from precommit

Chrome 146 lets you register a post-commit handler from within a precommit (navigate event) intercept. A precommit handler runs before the URL changes; the post-commit handler registered inside it runs after the commit. This gives fine-grained control over tasks that must split across the navigation boundary.

concepts

  1. Post-Commit Demo

    Intercept a navigation with a precommit handler and register a post-commit handler from inside it. The log shows the timing: precommit → URL changes → post-commit → finish. Demonstrates the ordering guarantee.

  2. Precommit vs Post-Commit

    Side-by-side: what's available before commit (old URL still active) vs after commit (new URL in the address bar). Shows which tasks belong in each phase — e.g. start loading spinner in precommit, update page state in post-commit.

  3. Intercept and restore

    Pit the new precommit/post-commit shape against classic intercept under a flaky fetch. Side-by-side events & address-bar trace show which strategy keeps the URL committed and which rolls back.

  4. SPA Router

    A simulated SPA router that intercepts navigations with a precommit handler (starts the loading bar), registers a post-commit handler (renders page content once the URL commits), and logs every phase in a live timeline.

why it shipped

SPA navigation orchestration often needs to run code both before and after the URL commits. Before this API, the only way to split work across the commit boundary was awkward — you'd have to use the navigate event for precommit work and then rely on navigatesuccess for post-commit work, which couldn't share context with the precommit handler easily. Chrome 146 lets precommit handlers register a post-commit callback via event.intercept({ handler: async () => { /* runs after commit */ } }), keeping related logic co-located.

the API

navigation.addEventListener('navigate', event => {
  if (!event.canIntercept) return;

  // Intercept: handler runs AFTER the URL commits
  event.intercept({
    // commit: 'after-transition' (default) or 'immediate'
    commit: 'after-transition',

    handler: async () => {
      // This runs AFTER the navigation URL has committed
      // (new URL is in the address bar)
      console.log('post-commit:', location.href);
      await loadPageContent();
    },
  });

  // Or use the shorthand to schedule code before and after:
  event.intercept({
    async handler() {
      // Chrome 146: use event.signal.reason to distinguish phases
      startLoadingSpinner();      // runs immediately (precommit)
      await fetchNewContent();    // awaited in post-commit phase
      stopLoadingSpinner();
    }
  });
});

references