svelte5-spa-router Svelte Themes

Svelte5 Spa Router

๐Ÿš€ Svelte 5 SPA Router

A simple, flexible, and lightweight SPA router specifically designed for Svelte 5 with runes support.

โœจ Features

  • ๐ŸŽฏ Svelte 5 Native: Built from ground up for Svelte 5 with runes
  • ๐Ÿ›ฃ๏ธ Dynamic Routing: Support for parameters (:id), optional parameters (:id?), and wildcards (/*)
  • โ“ Query Parameters: Full support for URL query strings and hash fragments
  • ๐Ÿ”„ Programmatic Navigation: Navigate with goto() function and reactive stores
  • ๐Ÿ“ฑ Browser History: Full back/forward button support with automatic link interception
  • ๐Ÿ—๏ธ SSR Compatible: Works perfectly with SvelteKit and server-side rendering
  • ๐Ÿ“ฆ TypeScript Ready: Fully typed for better developer experience
  • ๐Ÿชถ Lightweight: Zero external dependencies, minimal bundle size

๐Ÿ“ฆ Installation

npm install svelte5-spa-router
# or
yarn add svelte5-spa-router
# or
pnpm add svelte5-spa-router

๐ŸŽฏ Quick Start

Basic Setup

<!-- App.svelte -->
<script>
    import Router from 'svelte5-spa-router/Router.svelte';
    import Link from 'svelte5-spa-router/Link.svelte';
    import { router } from 'svelte5-spa-router';
    
    import Home from './routes/Home.svelte';
    import About from './routes/About.svelte';
    import UserProfile from './routes/UserProfile.svelte';
    import NotFound from './routes/NotFound.svelte';

    // Setup routes
    router.addRoute('/', Home);
    router.addRoute('/about', About);
    router.addRoute('/user/:id', UserProfile);
    router.setFallback(NotFound);
</script>

<nav>
    <Link href="/">Home</Link>
    <Link href="/about">About</Link>
    <Link href="/user/123">User Profile</Link>
</nav>

<Router />

Available Imports

// Components
import Router from 'svelte5-spa-router/Router.svelte';
import Link from 'svelte5-spa-router/Link.svelte';

// Router instance and functions
import { 
    router,           // Main router instance
    goto,             // Programmatic navigation
    getQueryParam,    // Get query parameter
    updateQueryParams // Update query params
} from 'svelte5-spa-router';

// Reactive stores
import {
    currentRoute,     // Current route info
    routeParams,      // Route parameters
    queryParams,      // Query parameters
    hashFragment      // Hash fragment
} from 'svelte5-spa-router';

๐Ÿ›ฃ๏ธ Route Setup

Setting Up Routes

import { router } from 'svelte5-spa-router';
import Home from './components/Home.svelte';
import About from './components/About.svelte';
import UserProfile from './components/UserProfile.svelte';
import BlogPost from './components/BlogPost.svelte';
import Search from './components/Search.svelte';
import AdminPanel from './components/AdminPanel.svelte';
import NotFound from './components/NotFound.svelte';

// Static Routes
router.addRoute('/', Home);
router.addRoute('/about', About);

// Dynamic Routes with Parameters
router.addRoute('/user/:id', UserProfile);
router.addRoute('/blog/:slug', BlogPost);
router.addRoute('/category/:type/item/:id', ItemDetail);

// Optional Parameters
router.addRoute('/search/:query?', Search);

// Wildcard Routes
router.addRoute('/admin/*', AdminPanel);

// Set fallback for 404
router.setFallback(NotFound);

๐Ÿงญ Navigation

<script>
    import Link from 'svelte5-spa-router/Link.svelte';
</script>

<Link href="/about">About Us</Link>
<Link href="/user/123">User Profile</Link>
<Link href="/search?q=svelte">Search Svelte</Link>
<Link href="/docs#introduction">Documentation</Link>

Programmatic Navigation

import { goto } from 'svelte5-spa-router';

// Simple navigation
goto('/about');

// With query parameters
goto('/search', { q: 'svelte', page: '1' });

// With hash fragment
goto('/docs', {}, 'introduction');

// Combined
goto('/search', { q: 'svelte', category: 'frontend' }, 'results');

๐Ÿ“Š Accessing Route Data

Route Parameters

<script>
    import { routeParams } from 'svelte5-spa-router';

    // Access route parameters reactively
    const userId = $derived($routeParams.id);
    const allParams = $derived($routeParams);
</script>

<h1>User Profile: {userId}</h1>
<p>All params: {JSON.stringify(allParams)}</p>

Query Parameters

<script>
    import { queryParams, getQueryParam, updateQueryParams } from 'svelte5-spa-router';

    // Get single parameter with default
    const searchQuery = $derived(getQueryParam('q', ''));

    // Get all parameters
    const allQueryParams = $derived($queryParams);

    // Update query parameters
    function updateSearch(newQuery) {
        updateQueryParams({ q: newQuery });
    }

    // Replace all query parameters
    function setFilters() {
        updateQueryParams({ category: 'tech', sort: 'date' }, true);
    }
</script>

<input bind:value={searchQuery} onchange={() => updateSearch(searchQuery)} />
<p>Current query: {searchQuery}</p>
<p>All params: {JSON.stringify(allQueryParams)}</p>

Hash Fragments

<script>
    import { hashFragment } from 'svelte5-spa-router';

    const currentHash = $derived($hashFragment);
</script>

<p>Current hash: {currentHash}</p>

๐Ÿ”ง API Reference

Components

Components

<Router>

Main router component that renders the current route based on the URL.

Usage:

<script>
    import Router from 'svelte5-spa-router/Router.svelte';
    import { router } from 'svelte5-spa-router';
    
    // Setup your routes first
    router.addRoute('/', HomeComponent);
    router.setFallback(NotFoundComponent);
</script>

<Router />

Link component with automatic active state handling and proper navigation.

Props:

  • href (string): Target URL
  • class (string, optional): CSS class for the link

Usage:

<script>
    import Link from 'svelte5-spa-router/Link.svelte';
</script>

<Link href="/about" class="nav-link">About</Link>

Functions

goto(path, queryParams?, hash?)

Navigate programmatically.

  • path: Target path
  • queryParams: Object of query parameters
  • hash: Hash fragment

getQueryParam(key, defaultValue?)

Get a specific query parameter.

updateQueryParams(params, replace?)

Update URL query parameters without navigation.

Stores

All stores are reactive and can be used with $ syntax:

  • currentRoute: Current route information { path, component, params }
  • routeParams: Parameters from current route
  • queryParams: Current query parameters object
  • hashFragment: Current hash fragment string
<script>
    import Link from 'svelte5-spa-router/Link.svelte';
</script>

<Link href="/" class="nav-link">Home</Link>

<style>
    :global(.nav-link) {
        text-decoration: none;
        color: #007acc;
        padding: 0.5rem 1rem;
        border-radius: 4px;
        transition: background-color 0.2s;
    }

    :global(.nav-link:hover) {
        background-color: #f0f0f0;
    }
</style>

๐Ÿ”’ Route Guards (Custom Implementation)

<!-- App.svelte -->
<script>
    import Router from 'svelte5-spa-router/Router.svelte';
    import { currentRoute, goto, router } from 'svelte5-spa-router';

    const protectedRoutes = ['/dashboard', '/profile'];

    // Route guard
    $effect(() => {
        if ($currentRoute && protectedRoutes.includes($currentRoute.path)) {
            if (!isAuthenticated()) {
                goto('/login');
            }
        }
    });

    function isAuthenticated() {
        // Your authentication logic
        return localStorage.getItem('token') !== null;
    }
</script>

<Router />

๐Ÿงช Testing

// vitest example
import { render, fireEvent } from '@testing-library/svelte';
import { goto, router } from 'svelte5-spa-router';
import Home from '../components/Home.svelte';
import About from '../components/About.svelte';
import App from '../App.svelte';

beforeEach(() => {
    // Setup routes for testing
    router.clearRoutes();
    router.addRoute('/', Home);
    router.addRoute('/about', About);
});

test('should navigate to about page', async () => {
    const { getByText } = render(App);

    await fireEvent.click(getByText('About'));
    expect(getByText('About Page')).toBeInTheDocument();
});

test('should handle dynamic routes', async () => {
    router.addRoute('/user/:id', UserProfile);
    goto('/user/123');
    
    const { getByText } = render(App);
    expect(getByText('User ID: 123')).toBeInTheDocument();
});

๐Ÿ”„ Migration from Other Routers

From svelte-spa-router

- import router from 'svelte-spa-router'
+ import Router from 'svelte5-spa-router/Router.svelte'
+ import { router } from 'svelte5-spa-router'

- <Router {routes} />
+ // Setup routes first
+ router.addRoute('/', HomeComponent);
+ router.setFallback(NotFoundComponent);
+ <Router />

From @roxi/routify

- import { router } from '@roxi/routify'
+ import { goto } from 'svelte5-spa-router'

- $router.goto('/path')
+ goto('/path')

๐Ÿ—๏ธ SvelteKit Integration

This router works perfectly with SvelteKit for client-side routing:

<!-- src/app.html or main component -->
<script>
    import Router from 'svelte5-spa-router/Router.svelte';
    import { router } from 'svelte5-spa-router';
    import Home from './routes/Home.svelte';
    import About from './routes/About.svelte';
    import NotFound from './routes/NotFound.svelte';

    // Setup routes
    router.addRoute('/', Home);
    router.addRoute('/about', About);
    router.setFallback(NotFound);
</script>

<Router />

๐Ÿ› Troubleshooting

SSR Issues

Make sure you're importing from the correct path and the router handles SSR automatically.

Route Not Matching

Check your route patterns and ensure they match the URL structure exactly.

Ensure you're using the Link component and not regular <a> tags.

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • Built for the amazing Svelte 5 and its new runes system
  • Inspired by various SPA routers in the ecosystem
  • Thanks to the Svelte community for feedback and suggestions

Made with โค๏ธ for the Svelte community

Report Bug โ€ข Request Feature โ€ข Documentation

Developing

Once you've created a project and installed dependencies with npm install (or pnpm install or yarn), start a development server:

npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open

Everything inside src/lib is part of your library, everything inside src/routes can be used as a showcase or preview app.

Building

To build your library:

npm run package

To create a production version of your showcase app:

npm run build

You can preview the production build with npm run preview.

To deploy your app, you may need to install an adapter for your target environment.

Publishing

Go into the package.json and give your package the desired name through the "name" option. Also consider adding a "license" field and point it to a LICENSE file which you can create from a template (one popular option is the MIT license).

To publish your library to npm:

npm publish

Top categories

Loading Svelte Themes