A lightweight, label-based router for Svelte 5. Define named routes that map to URL patterns, then use router.route reactively — not just to show components, but for any logic that depends on where you are.
npm install svelte-navigator-lite
Call createRouter once at your app's entry point (e.g. App.svelte):
import { createRouter, router } from 'svelte-navigator-lite';
import type { RouteList } from 'svelte-navigator-lite';
const routes: RouteList = {
'login': {
rootPath: 'login',
segments: [],
},
'dashboard': {
rootPath: 'dashboard',
segments: [],
},
};
createRouter(routes, 'dashboard'); // second argument is the default/fallback route
Then use router.route anywhere in your Svelte components — it's a reactive Svelte 5 $state value:
{#if router.is('login')}
<Login />
{:else if router.is('dashboard')}
<Dashboard />
{/if}
Every route has a rootPath — the first URL segment — and an array of segments for everything after it.
'login': {
rootPath: 'login', // matches /login
segments: [],
}
Use name to capture a URL segment into router.params:
'event': {
rootPath: 'event',
segments: [{ name: 'eventId' }], // matches /event/123
}
// router.params.eventId === '123'
Use enforceVal to require a literal string at that position:
'create-calendar': {
rootPath: 'calendar',
segments: [{ enforceVal: 'create' }], // matches /calendar/create only
}
enforceVal and name segments can be combined in any order:
'edit-event': {
rootPath: 'event',
segments: [
{ name: 'eventId' }, // matches /event/:eventId/edit
{ enforceVal: 'edit' },
],
}
Add optional: true to make a trailing segment optional. Optional segments must come after all required segments.
'event': {
rootPath: 'event',
segments: [
{ name: 'eventId' },
{ enforceVal: 'edit', optional: true }, // matches /event/123 AND /event/123/edit
],
}
Declared in searchParams. The route only matches if all listed params are present in the URL. Their values are captured into router.params.
'password-reset': {
rootPath: 'password-reset',
segments: [],
searchParams: ['token'], // matches /password-reset?token=abc only
}
// router.params.token === 'abc'
Declared in optionalSearchParams. Captured into router.params if present, silently ignored if absent. Do not affect whether the route matches.
'signup': {
rootPath: 'signup',
segments: [],
optionalSearchParams: ['redirect'], // matches /signup and /signup?redirect=/dashboard
}
// router.params.redirect === '/dashboard' (or undefined if absent)
router.navigate(route, params?)Navigate to a named route. Params are used to fill dynamic segments and search params.
router.navigate('event', { eventId: '123' });
// → /event/123
router.navigate('password-reset', { token: 'abc123' });
// → /password-reset?token=abc123
Throws if a required param is missing.
goto(path)Lower-level navigation to a raw path. Accepts an optional { replaceState: true } option to replace instead of push.
import { goto } from 'svelte-navigator-lite';
goto('/login');
goto('/login', { replaceState: true });
Guards run before navigation and redirect if their condition is met. fn returning true triggers the redirect.
import type { RouteGuard } from 'svelte-navigator-lite';
const guards = {
authenticated: {
fn: () => !auth.isValid(), // redirect if NOT authenticated
redirectTo: 'login',
} satisfies RouteGuard,
unauthenticated: {
fn: () => auth.isValid(), // redirect if already authenticated
redirectTo: 'dashboard',
} satisfies RouteGuard,
};
const routes: RouteList = {
'login': {
rootPath: 'login',
segments: [],
routeGuards: [guards.unauthenticated],
},
'dashboard': {
rootPath: 'dashboard',
segments: [],
routeGuards: [guards.authenticated],
},
};
Guards run in order and stop at the first redirect.
createRouter(routes, defaultRoute)Registers all routes and sets the fallback route. Parses the current URL immediately. Must be called once before using router.
router.routeThe label of the currently matched route. Falls back to defaultRoute if no route matches.
router.paramsAn object containing all captured values — path params, required search params, and any present optional search params.
router.notFoundtrue when the current URL did not match any defined route and the router fell back to defaultRoute. Use this to render a 404 state without needing a dedicated catch-all route.
{#if router.notFound}
<NotFound />
{:else if router.is('dashboard')}
<Dashboard />
{/if}
router.navigate(route, params?)Navigate to a named route, applying guards and building the URL from the route definition.
router.is(route)Returns true if router.route === route. Useful for active link styling.
class:active={router.is('dashboard')}
router.matches(routes)Returns true if router.route is any of the provided route names.
class:active={router.matches(['dashboard', 'settings'])}
pageA readable Svelte store that emits { url: URL } and updates on every navigation. Useful when you need the raw URL.
import { page } from 'svelte-navigator-lite';
$page.url.pathname;
rootPath is always required and must match the first URL segment exactly.required segments + 1 and total segments + 1 (the +1 accounts for rootPath).rootPath with nothing after it (e.g. /login not /login/extra).defaultRoute.