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;
}
}
});