Skip to content

Svelte Router adds routing to your Svelte apps. It's designed for Single Page Applications (SPA).

License

Notifications You must be signed in to change notification settings

thecodejack/svelte-router

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Svelte Router SPA

version license Code climate

What is Svelte Router SPA

Svelte Router adds routing to your Svelte apps. It keeps your routes organized in a single place.

With Svelte Router SPA you have all the features you need to create modern web applications with minimal configuration.

It's designed for Single Page Applications (SPA). If you need Server Side Rendering then consider using Sapper.

Features

  • Define your routes in a single interface
  • Layouts global, per page or nested.
  • Nested routes.
  • Named params.
  • Guards to protect urls. Public and private urls.
  • Track pageviews in Google Analytics (optional).
  • Use standard <a href="/about-us">About</a> elements to navigate between pages (or use <Navigate /> for bonus features).

Svelte Router is smart enought to inject the corresponding params to each Route component. Every Route component has information about their named params, query params and child route.

You can use all that information (availabe in the currentRoute property) to help you implement your business logic and secure the app.

Install

To install Svelte Router on your svelte app:

with npm

npm i svelte-router-spa

with Yarn

yarn add svelte-router-spa

Usage

Instead of having your routes spread inside your code Svelte Router SPA lets you define them inside a file where you can easily identify all available routes.

Add a routes.js file with your routes info. Example:

import Login from './views/public/login.svelte'
import PublicIndex from './views/public/index.svelte'
import PublicLayout from './views/public/layout.svelte'
import AdminLayout from './views/admin/layout.svelte'
import AdminIndex from './views/admin/index.svelte'
import EmployeesIndex from './views/admin/employees/index.svelte'

function userIsAdmin() {
  //check if user is admin and returns true or false
}

const routes = [
  {
    name: '/',
    component: PublicLayout
  },
  { name: 'login', component: Login, layout: PublicLayout },
  {
    name: 'admin',
    component: AdminLayout,
    onlyIf: { guard: userIsAdmin, redirect: '/login' },
    nestedRoutes: [
      { name: 'index', component: AdminIndex },
      {
        name: 'employees',
        component: '',
        nestedRoutes: [{ name: 'index', component: EmployeesIndex }, { name: 'show/:id', component: EmployeesShow }]
      }
    ]
  }
]

export { routes }

Import the routes into your main component (probably App.svelte)

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

<Router {routes} />

That's all

Layouts and route info

Every Route file will receive a currentRoute property with information about the current route, params, queries, etc.

You can add any number of layouts nested inside Router. For instance assuming that I want two layouts one for public pages and the other for private admin pages I would create these two files:

Filename: public_layout.svelte

<script>
  import { Route } from 'svelte-router-spa'
  import TopHeader from './top_header.svelte'
  export let currentRoute
  const params = {}
</script>

<div class="app">
  <TopHeader />
  <section class="section">
    <Route {currentRoute}  {params} />
  </section>
</div>

Filename: admin_layout.svelte

<script>
  import { Route } from "svelte-router-spa";

  export let currentRoute;
</script>

<div>
  <h1>Admin Layout</h1>
  <Route {currentRoute} {params} />
</div>

The route page will take care of rendering the appropriate component inside the layout. It will also pass a property called currentRoute to the component with information about the route, nested and query params.

Tip: You can have any number of layouts and you can nest them into each other as much as you want. Just remember to add a Route component where the content should be rendered inside the layout.

Tip: The Route component will pass a property to the rendered component named currentRoute with information about the current route, params, queries, etc.

Anatomy of a route

Each route is an object with the following elements:

{ name: 'about-us', component: About, layout: PublicLayout, redirectTo: 'https://www.alvareznavarro.es' }

name (required): The name that will be used in the url

component (required if no layout is present): A component that will be rendered when this route is active. If the route has nestedRoutes the component should be a Layout.

layout (required if no component is present): A component that acts as a layout (a container for other child components).

Either a component or a layout should be specified. Both can not be empty.

nestedRoutes: An array of routes.

redirectTo: A url or pathname (https://yourwebsite.com) or (/my-product).

onlyIf: An object to conditionally render a route. If guard returns true then route is rendered. If guard is false it redirects to redirect.

function userIsAdmin() {
  // do your checks here and returns true or false
}

{ name: 'admin', component: Admin, layout: PrivateLayout, onlyIf: { guard: userIsAdmin, redirect: '/login} }

Routes can contain as many nested routes as needed.

It can also contain as many layouts as needed. Layouts can be nested into other layouts.

In the following example both the home root ('/' and 'login' will use the same layout). Admin, employees and employeesShow will use the admin layout and employees will also use the employees layout, rendered inside the admin layout.

Example of routes:

const routes = [
  {
    name: '/',
    component: PublicIndex,
    layout: PublicLayout
  },
  { name: 'login', component: Login, layout: PublicLayout },
  {
    name: 'admin',
    component: AdminIndex,
    layout: AdminLayout,
    nestedRoutes: [
      {
        name: 'employees',
        component: EmployeesIndex,
        nestedRoutes: [
          {
            name: 'show/:id',
            component: EmployeesShowLayout,
            nestedRoutes: [{ name: 'index', component: EmployeesShow }, { name: 'list', component: EmployeesShowList }]
          }
        ]
      }
    ]
  }
]

The routes that this file will parse successfully are:

/
/login
/admin
/admin/employees
/admin/employees/show
/admin/employees/show/{id}
/admin/employees/show/{id}/list

API

Router

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

This is the main component that needs to be included before any other content as it holds information about your routes and which route should be rendered.

The simplest approach (although not required) is to have an App.svelte file like this:

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

  let options = { gaPageviews: true}
</script>

<Router {routes} {options} />

The layout and/or the component that matches the active route will be rendered inside Router.

The only option availabe now is gaPageviews that will record route changes as pageviews in Google Analytics. It's disabled by default.

Route

import { Route } from 'svelte-router-spa'

This component is only needed if you create a layout. It will take care of rendering the content for the child components or child layouts recursively. You can have as many nested layouts as you need.

The info about the current route will be received as a property so you need to define currentRoute and export it.

It will also accept an object called named params where you can send any aditional params to the rendered component. This is usefull if you add any logic in your template, to check user's permission for instance, and want to send extra info to the rendered component.

currentRoute has all the information about the current route and the child routes.

Route is smart enough to expose the named params in the route component where they will be rendered.

Example:

<script>
  import { Route } from 'svelte-router-spa'
  import TopHeader from './top_header.svelte'
  import FooterContent from './footer_content.svelte'
  export let currentRoute

  const params = { validCheck: true }
</script>

<div class="app">
  <TopHeader />
  <section class="section">
    <Route {currentRoute} {params} />
    <p>Route params are: {currentRoute.namedParams} and {currentRoute.queryParams)
  </section>
  <FooterContent />
</div>

currentRoute

This property is propagated from Route to the components it renders. It contains information about the current route and the child routes.

Example:

const routes = [
  {
    name: '/public',
    component: PublicLayout,
    nestedRoutes: [
      {
        name: 'about-us',
        component: 'AboutUsLayout',
        nestedRoutes: [{ name: 'company', component: CompanyPage }, { name: 'people', component: PeoplePage }]
      }
    ]
  }
]

That configuration will parse correctly the following routes:

/public
/public/about-us
/public/about-us/company
/public/about-us/people/:name

If the user visits /public/about-us/people/jack the following components will be rendered:

Router -> PublicLayout(Route) -> AboutUsLayout(Route) -> PeoplePage

Inside PeoplePage you can get all the information about the current route like this:

<script>
  export let currentRoute
</script>

<h1>Your name is: {currentRoute.namedParams.name}</h1>

This will render:

<h1>Your name is: Jack</h1>

Navigate

import { Navigate } from 'svelte-router-spa'

Navigate is a wrapper around the < a href="" > element to help you generate links quick and easily.

It adds an active class if the generated route is the active one.

Example:

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

<div class="app">
  <h1>My content</h1>
  <p>Now I want to generate a <Navigate to="admin/employees">link to /admin/employees</Navigate>
</div>

navigateTo

import { navigateTo } from 'svelte-router-spa'

navigateTo allows you to programatically navigate to a route from inside your app code.

navigateTo receives a path name as a param and will try to navigate to that route.

Example:

if (loginSuccess) {
  navigateTo('admin')
} else {
  navigateTo('login')
}

routeIsActive

import { routeIsActive } from 'svelte-router-spa'

Returns a boolean indicating if the path is the current active route.

This is useful, for instance to set an active class on a menu.

Params

  • pathName (required): A string with the path that you want to check.
  • includePath (optional | default is false): A boolean indicating if pathName should match exactly the current route or if it should be included.

The Navigate component does this automatically and adds an active class if the generated route is the active one. Navigate sets includePath to false

Example:

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

<a href="/contact-us" class:active={routeIsActive('/contact-us')}>
  Say hello
</a>

// If current route is /admin/companies/show/my-company

routeIsActive('admin') // returns false
routeIsActive('show/my-company') // returns false
routeIsActive('admin/companies/show/my-company') // returns true
routeIsActive('admin', true) // returns true
routeIsActive('show/my-company', true) // returns true
routeIsActive('my-company', true) // returns true
routeIsActive('other-company', true) // returns false

If includePath is true and the current route is /admin/companies/show/my-company

Not Found - 404

Svelte Router redirects to a 404.html page if a route is not found. You need to host and upload that page to your site. Most hosting providers support this configuration and will serve a 404.html page automatically for not found pages so chances are you already have one.

Google Analytics

If you want to track route changes as pageviews in Google Analytics just add

<Router {routes} options={{gaPageviews: true}} />

Credits

Svelte Router has been developed by Jorge Alvarez.

I would like to thank all the people that create issues and comment on Github. Your feedback is the best way of improving.

Contributors

Mark Kopenga

About

Svelte Router adds routing to your Svelte apps. It's designed for Single Page Applications (SPA).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 97.9%
  • HTML 2.1%