SPA Navigation

Router & SPA

Build single-page applications with seamless navigation, intelligent prefetching, and smooth view transitions. Create fast, responsive web apps that feel native.

Quick Start

Enable SPA routing in your FyneJS application with a simple configuration:

// Enable router with basic configuration
XTool.init({
  router: {
    enabled: true,
    transitionName: 'route',
    prefetchOnHover: true
  }
});

Once enabled, all internal navigation will be intercepted and handled as SPA transitions:

<!-- These links will trigger SPA navigation -->
<a href="/about">About Us</a>
<a href="/products/123">Product Details</a>
<a href="/contact#form">Contact Form</a>

How It Works

Container-Scoped Routing

Unlike traditional SPAs that take over the entire page, FyneJS router only manages navigation within your specified container (default: body).

This means you can embed SPA functionality in just part of your page—perfect for adding interactive sections to existing websites without full page takeover.

Intelligent Navigation

Setting location.href within components is automatically intercepted when the router is enabled—no need to use special navigation methods.

External links, downloads, and same-document navigation (hash changes) work normally while internal navigation is handled by the SPA router.

Built-in UX Features

History Management

Browser back/forward buttons work seamlessly with proper state restoration.

Scroll Restoration

Page scroll positions are saved and restored when navigating back/forward.

Hash Navigation

Hash changes and anchor links work normally alongside SPA navigation.

Configuration Options

Complete Router Configuration

XTool.init({
  router: {
    // Enable/disable SPA routing
    enabled: true,
    
    // Transition name for view transitions API
    transitionName: 'route',
    
    // Prefetch pages on hover/touch
    prefetchOnHover: true,
    
    // Navigation lifecycle hooks
    before: async (to, from, info) => {
      // Return false to cancel navigation
      if (to.includes('/admin') && !isAuthenticated) {
        return false;
      }
    },
    
    after: async (to, from, info) => {
      // Track page views, update analytics
      analytics.track('page_view', { url: to });
    },
    
    error: (error, to, from) => {
      // Handle navigation errors
      console.error('Navigation failed:', error);
    }
  }
});

Navigation Hooks

before

Called before navigation starts. Return false to cancel.

after

Called after successful navigation and DOM update.

error

Called when navigation fails or throws an error.

Hook Parameters

// All hooks receive these parameters:
before: (to, from, info) => {
  // to: destination URL (string)
  // from: current URL (string)
  // info: { source: 'link' | 'popstate' | 'program' }
  
  if (info.source === 'link') {
    // User clicked a link
  } else if (info.source === 'popstate') {
    // User used back/forward buttons
  } else {
    // Programmatic navigation
  }
}

Learn more: Router Hook Context for detailed information about hook parameters and usage patterns.

View Transitions

FyneJS router supports the View Transitions API for smooth page transitions in supported browsers:

/* Add CSS for custom transitions */
@view-transition {
  navigation: auto;
}

/* Customize the transition */
::view-transition-old(route) {
  animation: slide-out-left 0.3s ease-in-out;
}

::view-transition-new(route) {
  animation: slide-in-right 0.3s ease-in-out;
}

@keyframes slide-out-left {
  to { transform: translateX(-100%); }
}

@keyframes slide-in-right {
  from { transform: translateX(100%); }
}

Browser Support

View Transitions API is supported in Chrome 111+, Edge 111+, and other Chromium-based browsers. The router gracefully falls back to instant navigation in unsupported browsers.

Intelligent Prefetching

Improve perceived performance with automatic page prefetching:

Hover Prefetching

When enabled, pages are prefetched when users hover over or touch links:

prefetchOnHover: true

Manual Prefetching

Add prefetch hints manually for critical pages:

<link rel="prefetch" href="/about">

Best Practices

✅ Do

  • Use relative URLs for internal navigation
  • Implement proper error handling in hooks
  • Use prefetching for frequently visited pages
  • Test navigation with browser back/forward buttons

❌ Don't

  • Block navigation hooks with long-running operations
  • Rely on the router for forms with file uploads

Complete Example

Multi-page Application Setup

// app.js - Application setup
XTool.init({
  container: 'body',
  router: {
    enabled: true,
    transitionName: 'page-transition',
    prefetchOnHover: true,
    
    before: async (to, from, info) => {
      // Show loading indicator
      document.body.classList.add('navigating');
      
      // Authentication check
      if (to.includes('/admin') && !user.isAuthenticated) {
        alert('Please log in to access admin pages');
        return false;
      }
    },
    
    after: async (to, from, info) => {
      // Hide loading indicator
      document.body.classList.remove('navigating');
      
      // Update page title from <title> tag
      const title = document.querySelector('title')?.textContent;
      if (title) document.title = title;
      
      // Analytics tracking
      gtag('config', 'GA_MEASUREMENT_ID', {
        page_path: to
      });
    },
    
    error: (error, to, from) => {
      console.error('Navigation error:', error);
      document.body.classList.remove('navigating');
      
      // Fallback to full page load
      location.href = to;
    }
  }
});