FUNSTACK Router

HomeGetting StartedLearnAPI ReferenceExamplesFAQ
GitHub

Built with @funstack/router — A modern React router based on the Navigation API

Learn

Navigation APINested RoutesType SafetyForm ActionsHow Loaders RunError HandlingTransitionsSSRHow SSR WorksStatic Site GenerationSSR with LoadersRSCReact Server ComponentsRSC with Route Features

Navigation API

FUNSTACK Router is built on the Navigation API, a modern browser API that provides a unified way to handle navigation. This guide explains the key differences from the older History API and the benefits this brings to your application.

History API Limitations

The History API has been the foundation of single-page application routing for years, but it comes with significant limitations that make building routers more complex than necessary.

Reactive, not proactive: The popstate event fires after navigation has already occurred. This makes it difficult to intercept navigation, perform async operations like data fetching, or cancel navigation based on conditions.

// History API: popstate fires AFTER navigation
window.addEventListener("popstate", (event) => {
  // Too late! The URL has already changed.
  // We can only react to what happened.
  console.log("Navigated to:", location.pathname);
});

// For programmatic navigation, we must manually call pushState
// AND then update the UI ourselves
history.pushState(null, "", "/new-page");
updateUI(); // Manually trigger UI update

Fragmented event model: Different navigation types require different handling. Browser back/forward triggers popstate, but pushState and replaceState don't trigger any events. This leads to scattered navigation logic.

Custom Link components required: Since clicking an <a> tag causes a full page reload, routers must provide custom <Link> components that intercept clicks and call pushState instead.

The Navigation API Paradigm

The Navigation API fundamentally changes how navigation works by providing a single navigate event that fires before navigation commits. This allows routers to intercept and handle navigation declaratively.

// Navigation API: navigate event fires BEFORE navigation
navigation.addEventListener("navigate", (event) => {
  // Navigation hasn't happened yet - we can intercept it!
  const url = new URL(event.destination.url);

  // Check the navigation type
  console.log(event.navigationType); // "push", "replace", "reload", or "traverse"

  // Intercept and handle with async operations
  event.intercept({
    async handler() {
      // Fetch data, render components, etc.
      const data = await fetchPageData(url.pathname);
      renderPage(data);
      // Navigation completes when handler resolves
    }
  });
});

Key benefits of this approach:

  • Single unified event — All navigation types (link clicks, back/forward, programmatic) trigger the same navigate event
  • Interception with async support — The intercept() method lets you run async handlers before navigation completes
  • Built-in navigation type detection — event.navigationType tells you exactly what kind of navigation occurred

Native <a> Elements for SPA Links

One of the most practical benefits of the Navigation API is that standard <a> elements work for SPA navigation without any special handling. The router intercepts navigation events from native links automatically.

// With FUNSTACK Router, native <a> elements just work!
function Navigation() {
  return (
    <nav>
      {/* These are standard HTML anchor tags */}
      <a href="/home">Home</a>
      <a href="/about">About</a>
      <a href="/users/123">User Profile</a>
    </nav>
  );
}

// No special <Link> component needed for basic navigation
// The router intercepts the navigate event and handles it as SPA navigation

This means you can use standard HTML in your components, and navigation "just works". The router intercepts same-origin navigation events and handles them without a full page reload.

This approach has several advantages over custom Link components:

  • Standard HTML — No need to import and use special components for every link
  • Progressive enhancement — Links work even if JavaScript fails to load
  • Familiar patterns — Developers can use the <a> tag they already know

Accessing Navigation API Events

While FUNSTACK Router handles navigation for you, you can interact directly with the Navigation API when needed. This is useful for features like analytics tracking.

import { useEffect } from "react";

function App() {
  useEffect(() => {
    const controller = new AbortController();

    // Listen for successful navigation completion
    navigation.addEventListener(
      "navigatesuccess",
      () => {
        // Track page view for analytics
        analytics.trackPageView(location.pathname);
      },
      { signal: controller.signal }
    );

    return () => controller.abort();
  }, []);

  return <Router routes={routes} />;
}

The navigatesuccess event fires after navigation completes successfully, making it ideal for post-navigation actions. You can also use navigation.transition to track in-flight navigations or implement loading indicators.

Note: be careful when adding event listeners for navigate events since it may interfere with the router's own handling. Consider using onNavigate prop on the <Router> component for most use cases.

Other Navigation API Features

The Navigation API provides several advanced features that you can leverage directly when needed:

  • NavigationHistoryEntry — Each history entry has a unique id and key, plus a dispose event that fires when the entry is removed from history
  • Ephemeral info — Pass non-persisted context data during navigation via navigation.navigate(url, { info })
  • navigation.entries() — Access the full navigation history stack programmatically

For more details, see the MDN Navigation API documentation.

Key Takeaways

  • Native <a> elements work — No special Link component required for SPA navigation; the router intercepts standard anchor tags automatically
  • Direct API access when needed — Use events like navigatesuccess for scroll restoration, analytics, or other post-navigation actions