Routing

Effuse Router provides type-safe, declarative routing.

This page covers browser navigation. HTTP API routes, server middleware, SSR dispatch, and runtime adapters are documented in Server & APIs.

Setup

import {
  createRouter,
  createWebHistory,
  installRouter,
  type RouteRecord,
} from '@effuse/router';
import { HomePage } from './pages/Home';
import { DocsPage } from './pages/Docs';
import { ContactPage } from './pages/Contact';

const routes: RouteRecord[] = [
  { path: '/', name: 'home', component: HomePage },
  { path: '/docs/:slug', name: 'docs', component: DocsPage },
  { path: '/contact', name: 'contact', component: ContactPage },
];

export const router = createRouter({
  history: createWebHistory(),
  routes,
});

// Install router before creating app
installRouter(router);

Type-Safe Routes with defineRoutes

Use defineRoutes to create a type-safe route configuration that provides better autocompletion for Link and router.push.

import { defineRoutes } from '@effuse/router';

export const routes = defineRoutes([
  { path: '/', name: 'home', component: HomePage },
  { path: '/blog/:id', name: 'blog-post', component: PostPage },
] as const);

Protect your routes using global or per-route navigation guards.

// Global guard
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    return '/login'; // Redirect to login
  }
});

// Utility guards
import { createAuthGuard, createUnsavedChangesGuard } from '@effuse/router';

router.beforeEach(
  createAuthGuard({
    redirectTo: '/login',
    checkAuth: () => store.user.isLoggedIn,
  })
);

Use the Link component for navigation:

import { define } from '@effuse/core';
import { Link } from '@effuse/router';

const Nav = define({
  script: () => ({}),
  template: () => (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/docs/getting-started">Docs</Link>
      <Link to="/contact">Contact</Link>
    </nav>
  ),
});

RouterView

Use RouterView to render the matched component:

import { define } from '@effuse/core';
import { RouterView } from '@effuse/router';

const App = define({
  script: () => ({}),
  template: () => (
    <div class="app">
      <header>...</header>
      <main>
        <RouterView />
      </main>
      <footer>...</footer>
    </div>
  ),
});

Dynamic Route Parameters

Access route parameters, query strings, and hash in your components using the useRoute hook. First, define your route with dynamic segments:

const routes: RouteRecord[] = [
  {
    path: '/user/:userId',
    name: 'user-profile',
    component: UserProfile,
  },
];

Then access the parameters in your component:

import { define } from '@effuse/core';
import { useRoute } from '@effuse/router';

const UserProfile = define({
  script: () => {
    const route = useRoute();

    return {
      userId: route.params.userId, // Matches :userId in the path
      search: route.query.q, // Accesses ?q=... from URL
    };
  },
  template: ({ userId, search }) => (
    <div class="user-profile">
      <h1>User Profile</h1>
      <p>User ID: {userId}</p>
      {search && <p>Searching for: {search}</p>}
    </div>
  ),
});

Programmatic Navigation

Navigate programmatically using the useRouter hook:

import { define } from '@effuse/core';
import { useRouter } from '@effuse/router';

const DashboardButton = define({
  script: () => {
    const router = useRouter();

    return {
      goToSettings: () => {
        router.push('/settings');
      },
    };
  },
  template: ({ goToSettings }) => (
    <button onClick={goToSettings}>Go to Settings</button>
  ),
});

Router Composables

useRoute()

Returns the current route object. This object contains reactive properties that update whenever navigation occurs.

PropertyTypeDescription
pathstringThe pathname of the route.
fullPathstringThe complete URL including query and hash.
paramsRecord<string, string>Key-value pairs of dynamic segments.
queryRecord<string, string>Key-value pairs of the query string.
hashstringThe URL hash fragment.
matchedNormalizedRouteRecord[]Array of matched route records for nested routing.
namestring or undefinedThe name given to the route record.
metaRecord<string, any>Metadata defined on the route or its parents.

useRouter()

Returns the router instance for programmatic control.

MemberSignature / TypeDescription
currentRouteSignal<Route>Reactive signal of the current route.
routesNormalizedRouteRecord[]Readonly array of all registered routes.
isReadybooleanWhether the router has finished initialization.
push(to: RouteLocation) => voidNavigates to a new URL, adding a new entry to history.
replace(to: RouteLocation) => voidNavigate to a new URL by replacing the current entry.
back() => voidNavigates one step back in history.
forward() => voidNavigates one step forward in history.
go(delta: number) => voidNavigates n steps back or forward.
beforeEach(guard: NavigationGuard) => () => voidAdds a global navigation guard. Returns unregister function.
beforeResolve(guard: NavigationGuard) => () => voidAdds a guard called before navigation is resolved.
afterEach(hook: NavigationHook) => () => voidAdds a global navigation hook called after navigation.
resolve(to: RouteLocation) => ResolvedRouteResolves a route location to a normalized route object.
hasRoute(name: string) => booleanChecks if a route with the given name exists.
addRoute(route: RouteRecord, parentName?: string) => voidDynamically add a new route.
removeRoute(name: string) => voidDynamically remove a route by name.
getRoutes() => NormalizedRouteRecord[]Returns all normalized route records.

Next Steps