v147 ยท SPA Navigation Observer

SPA Navigation Observer

Drive a same-document route change and inspect the exact soft-navigation and interaction-contentful-paint contract: navigationType, numeric navigationId, interactionId, and largestInteractionContentfulPaint.

Origin Trial (Chrome 147-149). Native entries require the SoftNavigationHeuristics origin trial or chrome://flags/#soft-navigation-heuristics. When this browser does not expose the entry types, the page labels the output as a spec-shaped fallback.
Checking soft-navigation support...
Soft navigation candidate not run
navigationType
Route target
Same-document SPA surface /v147/softnavigation-performance-entry/spa-navigation-observer/
initial render

Home

Hero paint candidate

Click Run candidate to update the URL and replace this route content inside the same document.

paint target #route-hero
observer count soft-navigation: not exposed

Performance entries

SoftNavigationEntry

      
InteractionContentfulPaint

      
Runtime log
No events yet.

API code

const supportsSoftNav =
  PerformanceObserver.supportedEntryTypes.includes("soft-navigation");

const softNavsByInteraction = new Map();

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    softNavsByInteraction.set(entry.interactionId, entry);
    const largestPaint = entry.largestInteractionContentfulPaint ??
      entry.getLargestInteractionContentfulPaint?.();
    console.log(entry.navigationType, entry.navigationId, largestPaint);
  }
}).observe({ type: "soft-navigation", buffered: true });

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    const softNav = softNavsByInteraction.get(entry.interactionId);
    if (softNav) console.log("soft-nav LCP candidate", entry);
  }
}).observe({ type: "interaction-contentful-paint", buffered: true });

see also