Router API

Client-side routing for single-page applications.

SPA Package Required: The router is included in the SPA and Full packages only. It's not available in the Nano, Mini, Mini-pool, Lite, or Core packages.

wildflower.createRouter()

Create and configure the application router.

Signature

wildflower.createRouter(config: RouterConfig): Router

Config Options

OptionTypeDefaultDescription
mode 'hash' | 'history' 'hash' URL handling mode
routes RouteConfig[] [] Route definitions
defaultRoute string '/' Fallback route path
scrollBehavior function - Custom scroll handling
viewTransitions boolean false Enable View Transitions API for animated page changes

Example

const router = wildflower.createRouter({
    mode: 'history',
    routes: [
        { path: '/', component: 'home-page' },
        { path: '/about', component: 'about-page' },
        { path: '/users/:id', component: 'user-profile' },
        { path: '/products', component: 'product-list' },
        { path: '*', component: 'not-found' }
    ]
});
// Router is automatically initialized: no separate init() call needed

Route Configuration

Each route is an object with these properties:

RouteConfig

PropertyTypeDescription
path string URL path pattern
component string Component name to render
name string Named route for programmatic navigation
meta object Custom route metadata
beforeEnter function Route-specific guard, runs before entering this route
beforeLeave function Route-specific guard, runs before leaving this route
children RouteConfig[] Nested route definitions

Path Patterns

const routes = [
    // Static path
    { path: '/about', component: 'about-page' },

    // Dynamic parameter
    { path: '/users/:id', component: 'user-profile' },

    // Multiple parameters
    { path: '/posts/:category/:slug', component: 'blog-post' },

    // Optional parameter
    { path: '/search/:query?', component: 'search-results' },

    // Wildcard (catch-all)
    { path: '*', component: 'not-found' }
];

History Modes

Hash Mode (Default)

Uses URL hash for navigation. Works without server configuration.

// URLs like: example.com/#/users/123
wildflower.createRouter({
    mode: 'hash',
    routes: [...]
});

History Mode

Uses real URLs via History API. Requires server-side fallback configuration.

// URLs like: example.com/users/123
wildflower.createRouter({
    mode: 'history',
    routes: [...]
});
Server Configuration Required: History mode requires your server to return the main HTML file for all routes. Without this, direct URL access or page refresh will result in 404 errors.

Route Parameters

Access dynamic route parameters in your components.

Accessing Parameters

// Route: /users/:id
wildflower.component('user-profile', {
    state: {
        user: null,
        loading: true
    },

    async init() {
        // Access route params via the router
        const params = window.router.currentRoute.params;
        const userId = params.id;

        // Fetch user data
        const response = await fetch(`/api/users/${userId}`);
        this.user = await response.json();
        this.loading = false;
    }
});

Multiple Parameters

// Route: /posts/:category/:slug
wildflower.component('blog-post', {
    init() {
        const { category, slug } = window.router.currentRoute.params;
        console.log(`Loading post: ${category}/${slug}`);
    }
});

Query Strings

Access and manipulate URL query parameters.

Reading Query Parameters

// URL: /search?q=wildflower&page=2
wildflower.component('search-results', {
    init() {
        const query = window.router.currentRoute.query;
        console.log(query.q);    // 'wildflower'
        console.log(query.page); // '2'

        this.searchTerm = query.q || '';
        this.page = parseInt(query.page) || 1;
    }
});

Navigating with Query Parameters

// Add query parameters to navigation
router.navigate('/search', {
    query: {
        q: 'framework',
        category: 'javascript',
        page: 1
    }
});
// Results in: /search?q=framework&category=javascript&page=1

router.getRouteUrl()

Generate a URL string for a named route without navigating. Useful for building href attributes or constructing URLs programmatically.

Signature

router.getRouteUrl(name: string, params?: object, query?: object, hash?: string): string

Parameters

ParameterTypeDefaultDescription
name string - The name of the route (as defined in route configuration)
params object {} Route parameters to fill in dynamic segments
query object {} Query parameters to append as a query string
hash string '' Hash fragment to append (with or without leading #)

Returns

A URL string. Returns '/' if the named route is not found (and logs an error).

Example

const router = wildflower.createRouter({
    routes: [
        { path: '/users/:id', name: 'user-profile', component: 'user-profile' },
        { path: '/search/:query?', name: 'search', component: 'search-results' }
    ]
});

// Basic URL generation
router.getRouteUrl('user-profile', { id: 42 });
// => '/users/42'

// With query parameters
router.getRouteUrl('search', { query: 'wildflower' }, { page: 2 });
// => '/search/wildflower?page=2'

// Optional parameters are omitted when not provided
router.getRouteUrl('search');
// => '/search'

// With hash fragment
router.getRouteUrl('user-profile', { id: 42 }, {}, 'bio');
// => '/users/42#bio'

Route Guards

Control navigation based on conditions (authentication, permissions, etc.). Guards use a return-based API: return a value to control navigation, no callback needed.

Global Guards

const router = wildflower.createRouter({
    routes: [...]
});

// Before each route change: return-based
router.beforeEach(({ to, from }) => {
    const isAuthenticated = wildflower.getStore('auth').isLoggedIn;

    if (to.meta.requiresAuth && !isAuthenticated) {
        return '/login';   // Redirect
    }
    // Return nothing = allow navigation
});

// After each route change
router.afterEach(({ to, from }) => {
    // Analytics, scroll position, etc.
    analytics.pageView(to.path);
});

Per-Route Guards

const routes = [
    {
        path: '/admin',
        component: 'admin-dashboard',
        meta: { requiresAuth: true, requiresAdmin: true },
        beforeEnter: ({ to, from }) => {
            const user = wildflower.getStore('auth').user;
            if (!user || !user.isAdmin) {
                return '/unauthorized';  // Redirect
            }
            // Return nothing = allow
        }
    },
    {
        path: '/editor',
        component: 'document-editor',
        beforeLeave: ({ to, from }) => {
            const editor = wildflower.getStore('editor');
            if (editor.hasUnsavedChanges) {
                return false;  // Cancel navigation
            }
            // Return nothing = allow
        }
    }
];

Guard Return Values

Return ValueEffect
undefined / true Allow navigation
'/path' (string) Redirect to path
{ path: '/path', query?: {...} } Redirect to path with optional query parameters
false Cancel navigation

Lifecycle Hooks

Hook into the navigation lifecycle.

Router Hooks

const router = wildflower.createRouter({ routes: [...] });

// Before navigation: return-based guard
router.beforeEach(({ to, from }) => {
    console.log('Navigating from', from.path, 'to', to.path);
    // Return nothing = allow
});

// After navigation completes
router.afterEach(({ to, from }) => {
    console.log('Navigation complete');
});

// Navigation errors: listen via DOM event
document.addEventListener('route:error', (e) => {
    console.error('Navigation failed:', e.detail.error);
});

Component Route Hook

Components can respond to route changes via onRouteChange:

wildflower.component('dashboard', {
    // Called after navigation completes and this component is active
    onRouteChange(to, from) {
        console.log('Route changed to', to.path);
        // Refresh data, update UI, etc.
    }
});

DOM Events

The router dispatches CustomEvents on document for external integration:

EventWhenCancelable
route:beforeChangeBefore navigation startsYes
route:afterChangeAfter navigation completesNo
route:redirectWhen a redirect occursNo
route:errorOn navigation errorNo
route:notFoundWhen no route matchesNo

Nested Routes

Define child routes for nested views.

Configuration

const routes = [
    {
        path: '/users/:id',
        component: 'user-layout',
        children: [
            // /users/:id/profile
            { path: 'profile', component: 'user-profile' },
            // /users/:id/posts
            { path: 'posts', component: 'user-posts' },
            // /users/:id/settings
            { path: 'settings', component: 'user-settings' }
        ]
    }
];

Parent Component

<!-- user-layout component provides the wrapper -->
<div data-component="user-layout">
    <nav>
        <a href="/users/123/profile">Profile</a>
        <a href="/users/123/posts">Posts</a>
        <a href="/users/123/settings">Settings</a>
    </nav>

    <!-- Child route components render here -->
    <div data-router-view></div>
</div>

Router Instance

Properties and methods available on the router instance.

Property/MethodTypeDescription
router.currentRoute Route Current matched route object
router.currentRoute.params object Current route parameters
router.currentRoute.query object Current query parameters
router.navigate(path, options?) function Navigate to path (or { name, params, query } for named routes)
router.getRouteUrl(name, params?, query?, hash?) function Generate a URL string for a named route without navigating
router.beforeEach(guard) function Register global before guard: ({ to, from }) => result
router.afterEach(hook) function Register global after hook: ({ to, from }) => {}
router.isActive(pattern, opts?) function Check if pattern matches current route. opts: { exact: true }
router.abortNavigation() function Cancel an in-progress navigation
router.destroy() function Tear down the router and remove event listeners
router.viewTransitionsAvailable boolean Whether browser supports View Transitions API
router.viewTransitionsEnabled boolean Whether transitions are enabled AND supported
router.currentTransition ViewTransition | null Current active transition (during navigation)
router.setViewTransitions(enabled) function Enable/disable view transitions at runtime
router.on(event, callback) function Subscribe to router events (e.g., viewTransitionStart)