Convert Figma logo to code with AI

ItalyPaleAle logosvelte-spa-router

Router for SPAs using Svelte 3

1,542
106
1,542
28

Top Related Projects

18,419

web development, streamlined

A declarative Svelte routing library with SSR support

1,863

Automated Svelte routes

Quick Overview

Svelte-spa-router is a lightweight, client-side router for Single Page Applications (SPAs) built with Svelte. It provides a simple and efficient way to handle routing in Svelte applications, supporting both hash-based and path-based routing.

Pros

  • Easy to set up and use with a minimal learning curve
  • Supports both hash-based and path-based routing
  • Offers advanced features like nested routes, route parameters, and programmatic navigation
  • Lightweight and performant, with no external dependencies

Cons

  • Limited to client-side routing, not suitable for server-side rendering
  • May require additional configuration for deployment on some hosting platforms
  • Documentation could be more comprehensive for advanced use cases
  • Smaller community compared to some other routing solutions

Code Examples

  1. Basic route configuration:
import Home from './routes/Home.svelte'
import About from './routes/About.svelte'
import NotFound from './routes/NotFound.svelte'

const routes = {
  '/': Home,
  '/about': About,
  '*': NotFound,
}
  1. Using the Router component:
<script>
  import Router from 'svelte-spa-router'
  import { routes } from './routes'
</script>

<Router {routes} />
  1. Programmatic navigation:
import { push, pop, replace } from 'svelte-spa-router'

// Navigate to a new route
push('/about')

// Go back to the previous route
pop()

// Replace the current route
replace('/new-route')

Getting Started

  1. Install the package:

    npm install svelte-spa-router
    
  2. Define your routes in a separate file (e.g., routes.js):

    import Home from './routes/Home.svelte'
    import About from './routes/About.svelte'
    
    export const routes = {
      '/': Home,
      '/about': About,
    }
    
  3. Use the Router component in your main App.svelte file:

    <script>
      import Router from 'svelte-spa-router'
      import { routes } from './routes'
    </script>
    
    <Router {routes} />
    
  4. Create your route components (e.g., Home.svelte, About.svelte) and start building your SPA!

Competitor Comparisons

18,419

web development, streamlined

Pros of SvelteKit

  • Full-featured framework for building server-rendered and static sites
  • Built-in development server, routing, and code-splitting
  • Seamless integration with Svelte's reactivity system

Cons of SvelteKit

  • Steeper learning curve due to its comprehensive nature
  • May be overkill for simple single-page applications
  • Requires server-side setup for full functionality

Code Comparison

svelte-spa-router:

import Router from 'svelte-spa-router'
import Home from './routes/Home.svelte'
import About from './routes/About.svelte'

const routes = {
  '/': Home,
  '/about': About
}

SvelteKit:

// src/routes/+page.svelte
<h1>Welcome to SvelteKit</h1>

// src/routes/about/+page.svelte
<h1>About Page</h1>

// File-based routing, no explicit configuration needed

svelte-spa-router is a lightweight client-side router for Svelte applications, ideal for simple single-page apps. It offers easy setup and minimal overhead.

SvelteKit, on the other hand, is a full-fledged framework that provides a more comprehensive solution for building Svelte applications. It includes server-side rendering, static site generation, and more advanced routing capabilities.

Choose svelte-spa-router for simple SPAs with client-side routing, and SvelteKit for more complex applications that require server-side rendering or static site generation.

A declarative Svelte routing library with SSR support

Pros of svelte-routing

  • Supports nested routes, allowing for more complex routing structures
  • Provides a Link component for easy navigation between routes
  • Offers a navigate function for programmatic navigation

Cons of svelte-routing

  • Less actively maintained compared to svelte-spa-router
  • Fewer stars and contributors on GitHub
  • Limited documentation and examples available

Code Comparison

svelte-routing:

import { Router, Link, Route } from "svelte-routing";

<Router>
  <nav>
    <Link to="/">Home</Link>
    <Link to="/about">About</Link>
  </nav>
  <Route path="/" component={Home} />
  <Route path="/about" component={About} />
</Router>

svelte-spa-router:

import Router from 'svelte-spa-router'
import { link } from 'svelte-spa-router'

const routes = {
  '/': Home,
  '/about': About
}

<Router {routes} />
<a href="/" use:link>Home</a>
<a href="/about" use:link>About</a>

Both libraries provide routing solutions for Svelte applications, but they differ in their approach and feature set. svelte-routing offers a more React-like syntax with nested routes support, while svelte-spa-router provides a simpler API with better performance for single-page applications. The choice between the two depends on the specific needs of your project and personal preference.

1,863

Automated Svelte routes

Pros of Routify

  • Automatic route generation based on file structure
  • Built-in support for nested layouts and route transitions
  • More comprehensive documentation and examples

Cons of Routify

  • Steeper learning curve due to more advanced features
  • Potentially more complex setup for simple projects
  • Larger bundle size compared to svelte-spa-router

Code Comparison

Routify:

<script>
  import { Router } from "@roxi/routify";
  import { routes } from "../.routify/routes";
</script>

<Router {routes} />

svelte-spa-router:

<script>
  import Router from 'svelte-spa-router';
  import { routes } from './routes';
</script>

<Router {routes} />

Both libraries offer similar basic usage, but Routify's file-based routing system can lead to more concise route definitions. svelte-spa-router requires manual route configuration, which can be more explicit but potentially more verbose for larger applications.

Routify provides a more feature-rich solution with automatic route generation and nested layouts, making it suitable for complex applications. However, this comes at the cost of a steeper learning curve and potentially larger bundle size.

svelte-spa-router offers a simpler, lightweight solution that may be preferable for smaller projects or developers who prefer more manual control over their routing configuration.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Svelte 3 Up and Running

Want to learn Svelte 3 and how to build a Single-Page App (SPA) with it (and with this router)? Check out my book Svelte 3 Up and Running on Amazon.

svelte-spa-router

Build Status npm GitHub

This module is a router for Svelte 3 and 4 applications, specifically optimized for Single Page Applications (SPA).

Main features:

  • Leverages hash-based routing, which is optimal for SPAs and doesn't require any server-side processing
  • Insanely simple to use, and has a minimal footprint
  • Uses the tiny regexparam for parsing routes, with support for parameters (e.g. /book/:id?) and more

This module is released under MIT license.

Video

"So you want to pick a router?" talk by @ItalyPaleAle at Svelte Summit 2020. Includes an explanation of the two kinds of routers and a demo of svelte-spa-router.
(Click on the cover image to play the video on YouTube)

Click to play video: 'So you want to pick a router?'

Hash-based routing

With hash-based routing, navigation is possible thanks to storing the current view in the part of the URL after #, called "hash" or "fragment".

For example, if your SPA is in a static file called index.html, your URLs for navigating within the app look something like index.html#/profile, index.html#/book/42, etc. (The index.html part can usually be omitted for the index file, so you can just create URLs that look like http://example.com/#/profile).

When I created this component, other routers for Svelte 3+ implemented navigation using the HTML5 history API. While those URLs look nicer (e.g. you can actually navigate to http://example.com/profile), they are not ideal for static Single Page Applications. In order for users to be able to share links or even just refresh the page, you are required to have a server on the backend processing the request, and building fully-static apps is much harder as a consequence.

Hash-based routing is simpler, works well even without a server, and it's generally better suited for static SPAs, especially when SEO isn't a concern, as is the case when the app requires authentication. Many popular apps use hash-based routing, including GMail!

Sample code

Check out the code in the examples folder for some usage examples.

To run the samples, clone the repository, install the dependencies, then build each sample using Rollup:

git clone https://github.com/ItalyPaleAle/svelte-spa-router
cd svelte-spa-router
npm install

# Navigate to a sample
cd examples/…
# For example
cd examples/basic-routing

# Build and run (in the folder of a sample)
npx rollup -c
npx serve -n -l 5050 dist

The sample will be running at http://localhost:5050

Starter template

You can find a starter template with Svelte 4 and svelte-spa-router at italypaleale/svelte-spa-router-template.

To use the template:

npx degit italypaleale/svelte-spa-router-template svelte-app
cd svelte-app

More information can be found on the template's repo.

Using svelte-spa-router

You can include the router in any project using Svelte 3 or 4.

Install from NPM

To add svelte-spa-router to your project:

npm install svelte-spa-router

Supported browsers

svelte-spa-router aims to support modern browsers, including recent versions of:

  • Chrome
  • Edge ("traditional" and Chromium-based)
  • Firefox
  • Safari

Support for Internet Explorer is not a goal for this project. Some users have reportedly been able to use svelte-spa-router with IE11 after transpilation (e.g. with Babel), but this is not guaranteed.

Define your routes

Each route is a normal Svelte component, with the markup, scripts, bindings, etc. Any Svelte component can be a route.

The route definition is just a JavaScript dictionary (object) where the key is a string with the path (including parameters, etc), and the value is the route object.

For example:

import Home from './routes/Home.svelte'
import Author from './routes/Author.svelte'
import Book from './routes/Book.svelte'
import NotFound from './routes/NotFound.svelte'

const routes = {
    // Exact path
    '/': Home,

    // Using named parameters, with last being optional
    '/author/:first/:last?': Author,

    // Wildcard parameter
    '/book/*': Book,

    // Catch-all
    // This is optional, but if present it must be the last
    '*': NotFound,
}

Routes must begin with / (or * for the catch-all route).

Alternatively, you can also define your routes using custom regular expressions, as explained below.

Note that the order matters! When your users navigate inside the app, the first matching path will determine which route to load. It's important that you leave any "catch-all" route (e.g. a "Page not found" one) at the end.

Include the router view

To display the router, in a Svelte component (usually App.svelte), first import the router component:

import Router from 'svelte-spa-router'

Then, display the router anywhere you'd like by placing the component in the markup. For example:

<body>
    <Router {routes}/>
</body>

The routes prop is the dictionary defined above.

That's it! You already have all that you need for a fully-functional routing experience.

Dynamically-imported components and code-splitting

Starting with version 3.0, svelte-spa-router supports dynamically-imported components (via the import() construct). The advantage of using dynamic imports is that, if your bundler supports that, you can enable code-splitting and reduce the size of the bundle you send to your users. This has been tested with bundlers including Rollup and Webpack.

To use dynamically-imported components, you need to leverage the wrap method (which can be used for a variety of actions, as per the docs on route wrapping). First, import the wrap method:

import {wrap} from 'svelte-spa-router/wrap'

Then, in your route definition, wrap your routes using the wrap method, passing a function that returns the dynamically-imported component to the asyncComponent property:

wrap({
    asyncComponent: () => import('./Foo.svelte')
})

Note: the value of asyncComponent must be the definition of a function returning a dynamically-imported component, such as asyncComponent: () => import('./Foo.svelte').
Do not use asyncComponent: import('./Foo.svelte'), which is a function invocation instead.

For example, to make the Author and Book routes from the first example dynamically-imported, we'd update the code to:

// Import the wrap method
import {wrap} from 'svelte-spa-router/wrap'

// Note that Author and Book are not imported here anymore, so they can be imported at runtime
import Home from './routes/Home.svelte'
import NotFound from './routes/NotFound.svelte'

const routes = {
    '/': Home,

    // Wrapping the Author component
    '/author/:first/:last?': wrap({
        asyncComponent: () => import('./routes/Author.svelte')
    }),

    // Wrapping the Book component
    '/book/*': wrap({
        asyncComponent: () => import('./routes/Book.svelte')
    }),

    // Catch-all route last
    '*': NotFound,
}

The wrap method accepts an object with multiple properties and enables other features, including: setting a "loading" component that is shown while a dynamically-imported component is being requested, adding pre-conditions (route guards), passing static props, and adding custom user data.

You can learn more about all the features of wrap in the documentation for route wrapping.

Navigating between pages

You can navigate between pages with normal anchor (<a>) tags. For example:

<a href="#/book/123">Thus Spoke Zarathustra</a>

The use:link action

Rather than having to type # before each link, you can also use the use:link action:

<script>
import {link} from 'svelte-spa-router'
</script>
<a href="/book/321" use:link>The Little Prince</a>

The use:link action accepts an optional parameter opts, which can be one of:

  • A dictionary {href: '/foo', disabled: false} where both keys are optional:
    • If you set a value for href, your link will be updated to point to that address, reactively (this will always take precedence over href attributes, if present)
    • Setting disabled: true disables the link, so clicking on that would have no effect
  • A string with a destination (e.g. /foo), which is a shorthand to setting {href: '/foo'}.

For example:

<script>
import {link} from 'svelte-spa-router'
let myLink = "/book/456"
</script>
<!-- Note the {{...}} notation because we're passing an object as parameter for a Svelte action -->
<a use:link={{href: myLink, disabled: false}}>The Biggest Princess</a>

The above is equivalent to:

<script>
import {link} from 'svelte-spa-router'
let myLink = "/book/456"
</script>
<a use:link={myLink}>The Biggest Princess</a>

Changing the value of myLink will reactively update the link's href attribute.

Navigating programmatically

You can navigate between pages programmatically too:

import {push, pop, replace} from 'svelte-spa-router'

// The push(url) method navigates to another page, just like clicking on a link
push('/book/42')

// The pop() method is equivalent to hitting the back button in the browser
pop()

// The replace(url) method navigates to a new page, but without adding a new entry in the browser's history stack
// So, clicking on the back button in the browser would not lead to the page users were visiting before the call to replace()
replace('/book/3')

These methods can be used inside Svelte markup too, for example:

<button on:click={() => push('/page')}>Go somewhere</button>

The push, pop and replace methods perform navigation actions only in the next iteration ("tick") of the JavaScript event loop. This makes it safe to use them also inside onMount callbacks within Svelte components.

These functions return a Promise that resolves with no value once the navigation has been triggered (in the next tick of the event loop); however, please note that this will likely be before the new page has rendered.

Parameters from routes

svelte-spa-router uses regexparam to parse routes, so you can add optional parameters to the route. Basic syntax is:

  • /path matches /path exactly (and only that)
  • /path/:id matches /path/ followed by any string, which is a named argument id
  • /path/:id/:version? allows for an optional second named argument version
  • /path/* matches /path/ followed by anything, using a non-named argument

Please refer to the documentation of regexparam for more details.

If your route contains any parameter, they will be made available to your component inside the params dictionary.

For example, for a route /name/:first/:last?, you can create this Svelte component:

<p>Your name is: <b>{params.first}</b> <b>{#if params.last}{params.last}{/if}</b></p>
<script>
// You need to define the component prop "params"
export let params = {}
</script>

Non-named arguments are returned as params.wild.

Getting the current page

You can get the current page from the $location readable store. This is a Svelte store, so it can be used reactively too.

<script>
import {location} from 'svelte-spa-router'
</script>
<p>The current page is: {$location}</p>

Querystring parameters

You can also extract "querystring" parameters from the hash of the page. This isn't the real querystring, as it's located after the # character in the URL, but it can be used in a similar way. For example: #/books?show=authors,titles&order=1.

When svelte-spa-router finds a "querystring" in the hash, it separates that from the location and returns it as a string in the Svelte store $querystring. For example:

<script>
import {location, querystring} from 'svelte-spa-router'
</script>
<p>The current page is: {$location}</p>
<p>The querystring is: {$querystring}</p>

With the example above, this would print:

The current page is: /books
The querystring is: show=authors,titles&order=1

It's important to note that, to keep this component lightweight, svelte-spa-router does not parse the "querystring". If you want to parse the value of $querystring, you can use URLSearchParams available in all modern browsers, or third-party modules such as qs.

Highlight active links

svelte-spa-router has built-in support for automatically marking links as "active", with the use:active action.

For example, you can use the code below to add the CSS class active to links that are active:

<script>
import {link} from 'svelte-spa-router'
import active from 'svelte-spa-router/active'
</script>

<style>
/* Style for "active" links; need to mark this :global because the router adds the class directly */
:global(a.active) {
    color: red;
}
</style>

<a href="/hello/user" use:link use:active={{path: '/hello/*', className: 'active', inactiveClassName: 'inactive'}}>Say hi!</a>
<a href="/hello/user" use:link use:active={'/hello/*'}>Say hi with a default className!</a>
<a href="/hello/user" use:link use:active>Say hi with all default options!</a>

The active action accepts a dictionary options as argument:

  • options.path: the path that, when matched, makes the link active. In the first example above, we want the link to be active when the route is /hello/* (the asterisk matches anything after that). As you can see, this doesn't have to be the same as the path the link points to. When options.path is omitted or false-y, it defaults to the path specified in the link's href attribute. This parameter can also be a regular expression that will mark the link as active when it matches: for example, setting to the regular expression /^\/*\/hi$/ will make the link active when it starts with / and ends with /hi, regardless of what's in between.
  • options.className: the name of the CSS class to add. This is optional, and it defaults to active if not present.
  • options.inactiveClassName: the name of the CSS class to add when the link is not active. This is optional, and it defaults to nothing if not present.

As a shorthand, instead of passing a dictionary as options, you can pass a single string or regular expression that will be interpreted as options.path.

Define routes with custom regular expressions

Since version 1.2 of svelte-spa-router, it's possible to define routes using custom regular expressions too, allowing for greater flexibility. However, this requires defining routes using a JavaScript Map rather than an object:

import Home from './routes/Home.svelte'
import Name from './routes/Name.svelte'
import NotFound from './routes/NotFound.svelte'

const routes = new Map()

// You can still use strings to define routes
routes.set('/', Home)
routes.set('/hello/:first/:last?', Name)

// The keys for the next routes are regular expressions
// You will very likely always want to start the regular expression with ^
routes.set(/^\/hola\/(.*)/i, Name)
routes.set(/^\/buongiorno(\/([a-z]+))/i, Name)

// Catch-all, must be last
routes.set('*', NotFound)

When you define routes as regular expressions, the params prop is populated with an array with the result of the matches from the regular expression.

For example, with this Name.svelte route:

<p>Params is: <code>{JSON.stringify(params)}</code></p>
<script>
// You need to define the component prop "params"
export let params = {}
</script>

When visiting #/hola/amigos, the params prop will be ["/hola/amigos","amigos"].

This is consistent with the results of RegExp.prototype.exec().

When defining a route using a regular expression, you can optionally use named capturing groups. When using those, in addition to finding your matches in the params prop, you can find the matches for named capturing groups in params.group.
For example, consider the route:

routes.set(/^\/book\/(?<title>[a-z]+)$/, Book)

When visiting /#/book/mytitle, the params prop will be an array with ["/book/mytitle", "mytitle"], and params.groups will be a dictionary with {"title": "mytitle"}.

Advanced usage

Check out the Advanced Usage documentation for using:

NPM DownloadsLast 30 Days