A lightweight and flexible router for Svelte applications with advanced nested routing capabilities, leveraging path-to-regexp for powerful route matching.
pnpm install sly-svelte-router
<script lang="ts">
import { Router } from 'sly-svelte-router';
import type { Routes } from 'sly-svelte-router';
const routes: Routes = {
'/': () => import('./routes/Home.svelte'),
'/about': () => import('./routes/About.svelte'),
'/users/:id': () => import('./routes/UserDetail.svelte'),
'/legacy-path': '/about', // Redirect
};
</script>
<Router {routes} fallback={() => import('./routes/404.svelte')}>
<div>Loading...</div>
</Router>
For advanced use cases where you need precise control over router initialization, you can use initRouter()
instead of the Router component:
<script lang="ts">
import { initRouter, navigate } from 'sly-svelte-router';
import { onMount } from 'svelte';
onMount(() => {
// Initialize router manually - handles URL changes and navigation
initRouter();
// You'll need to implement your own route resolution logic
// This approach is for advanced users who want full control
});
</script>
<!-- Custom routing implementation -->
<div>Your custom route rendering logic here</div>
Create complex nested route structures by using Router components within your route components:
<!-- routes/Admin.svelte -->
<script lang="ts">
import { Router } from 'sly-svelte-router';
import type { Routes } from 'sly-svelte-router';
const routes: Routes = {
'/': () => import('./admin/Dashboard.svelte'),
'/users': () => import('./admin/Users.svelte'),
'/users/:id': () => import('./admin/UserDetail.svelte'),
'/settings': () => import('./admin/Settings.svelte'),
};
</script>
<div class="admin-layout">
<nav><!-- Admin navigation --></nav>
<main>
<Router {routes} fallback={() => import('./admin/NotFound.svelte')}>
<div>Loading admin content...</div>
</Router>
</main>
</div>
URL Examples:
/admin
→ Admin layout + Dashboard/admin/users
→ Admin layout + Users list /admin/users/123
→ Admin layout + User detail for ID 123/admin/invalid
→ Admin layout + Admin-specific 404 pageThe router uses a sophisticated segment-by-segment resolution strategy:
Example with /shop/products/123
:
Main Router: matches '/shop' → loads Shop component, remaining: ['products', '123']
Shop Router: matches '/products/:id' → loads ProductDetail, remaining: []
'/users/:id': () => import('./routes/UserDetail.svelte')
'/posts/:category/:id': {
name: 'post-detail',
component: () => import('./routes/PostDetail.svelte')
}
'/old-users': '/users', // Simple redirect
'/legacy/:id': '/users/:id' // Parameter-preserving redirect
Protect routes with async guard functions:
'/admin': {
name: 'admin',
component: () => import('./routes/Admin.svelte'),
guard: async () => {
const isAuthenticated = await checkAuth();
if (!isAuthenticated) {
// Redirect with state
return {
path: '/login',
state: { message: 'Please login to access admin area' }
};
}
return null; // Allow access
}
}
All route components receive a standardized route
prop containing route information. The examples use Svelte 5's rune syntax ($props()
, $derived
) for modern, reactive component development:
interface RouteProps {
params?: RouteParams // Route parameters from URL
error?: ErroneousRouteStore // Error info for fallback components
state?: any // Navigation state data
}
<!-- UserDetail.svelte -->
<script lang="ts">
import type { RouteProps } from 'sly-svelte-router';
let { route }: { route: RouteProps } = $props();
// For /users/123, route.params.id === '123'
const userId = $derived(route.params?.id);
</script>
<h1>User: {userId}</h1>
Supported Parameter Types:
:id
- Required parameter:id?
- Optional parameter :path*
- Zero or more segments:path+
- One or more segmentsAccess state passed during navigation or from guards:
<script lang="ts">
import type { RouteProps } from 'sly-svelte-router';
let { route }: { route: RouteProps } = $props();
// Access state from guard redirects
const message = $derived(route.state?.message);
</script>
{#if message}
<div class="alert">{message}</div>
{/if}
Fallback components receive error information through the same interface:
<!-- 404.svelte -->
<script lang="ts">
import type { RouteProps } from 'sly-svelte-router';
let { route }: { route: RouteProps } = $props();
const errorPath = $derived(route.error?.path);
</script>
<h1>404 - Not Found</h1>
<p>The path "{errorPath}" could not be found.</p>
import { navigate } from 'sly-svelte-router';
// Navigate to a new route
navigate('/users/123');
// Navigate with state
navigate('/dashboard', { from: 'login', userId: 123 });
// Works with nested routes
navigate('/admin/users/456');
Fallbacks handle unmatched routes and can be defined at any router level:
<!-- Main app fallback -->
<Router {routes} fallback={() => import('./routes/404.svelte')}>
<div>Loading...</div>
</Router>
<!-- Admin-specific fallback -->
<Router {adminRoutes} fallback={() => import('./admin/NotFound.svelte')}>
<div>Loading admin...</div>
</Router>
Fallback Resolution:
/ → Homepage
/products → Product list
/products/123 → Product detail
/cart → Shopping cart
/admin → Admin dashboard
/admin/products → Admin product management
/admin/orders → Admin order management
<!-- App.svelte -->
<script lang="ts">
const routes = {
'/': () => import('./routes/Home.svelte'),
'/products': () => import('./routes/Products.svelte'),
'/products/:id': () => import('./routes/ProductDetail.svelte'),
'/cart': () => import('./routes/Cart.svelte'),
'/admin': () => import('./routes/Admin.svelte'),
};
</script>
<Router {routes} fallback={() => import('./routes/404.svelte')}>
<div>Loading...</div>
</Router>
Full TypeScript support with strict typing:
import type { Routes, RouteProps, RouteDefinition } from 'sly-svelte-router';
const routes: Routes = {
'/users/:id': () => import('./UserDetail.svelte')
};
// In your component (Svelte 5)
let { route }: { route: RouteProps } = $props();
// Type-safe access to params
const userId = $derived(route.params?.id);
Router
Componentroutes: Routes
- Route configuration objectfallback?: RouteDefinition
- Fallback component for unmatched routeschildren?
- Loading component (rendered during route transitions)navigate(path: string, state?: any)
Programmatic navigation function with optional state.
initRouter()
Manual router initialization function. Use this instead of the Router component when you need to implement custom route resolution logic. This function sets up URL change listening and navigation event handling, but you'll need to implement your own route matching and component rendering.
Routes
- Route configuration object typeRouteDefinition
- Union type for route definitionsRouteProps
- Props interface for route componentsRouteParams
- Route parameter object typeRouteComponent
- Lazy-loaded component typeRouteGuard
- Guard function type for route protectionMIT
Contributions welcome! Please feel free to submit a Pull Request.