Data & Declarative Routing Library – svelte-router

svelte-router is a lightweight, accessible, high-performance Svelte routing library that implements React Router’s API pattern for building modern single-page applications with proper navigation and data loading.

Features

Multiple Router Types: BrowserRouter, HashRouter, MemoryRouter, and StaticRouter for different deployment scenarios.

🔄 Data Loading Integration: Built-in loader and action functions with proper error handling and loading states.

🛠️ Nested Routing Support: Full support for nested routes and layout components with outlet rendering.

🎯 Progressive Enhancement: Functions correctly with or without JavaScript enabled in the browser.

How to Use It

1. Install the package in your project.

# Yarn
$ yarn add @hvniel/svelte-router
# NPM
$ npm install @hvniel/svelte-router
# PNPM
$ pnpm install @hvniel/svelte-router

2. Data Routing:

This is the more modern approach, where you define your routes as a centralized JavaScript object. I’ve found this pattern scales very well for larger applications.

You create a router instance with createBrowserRouter and provide it to your app with the RouterProvider component.

<!-- App.svelte -->
<script>
  import { createBrowserRouter, RouterProvider } from '@hvniel/svelte-router';
  import Root from './routes/Root.svelte';
  import Home from './routes/Home.svelte';
  import User, { loader as userLoader } from './routes/User.svelte';
  const router = createBrowserRouter([
    {
      path: "/",
      Component: Root,
      children: [
        { index: true, Component: Home },
        {
          path: "/users/:id",
          Component: User,
          // The loader function fetches data before the component renders
          loader: userLoader,
        },
      ],
    },
  ]);
</script>
<RouterProvider {router} />

Inside a component, you can access the data from a loader using the useLoaderData hook.

<!-- routes/User.svelte -->
<script module>
  // This loader runs on the server or in the browser before navigation
  export const loader = async ({ params }) => {
    const response = await fetch(`/api/users/${params.id}`);
    return response.json();
  };
</script>
<script>
  import { useLoaderData } from '@hvniel/svelte-router';
  // The hook gives you the data returned from the loader
  const user = useLoaderData();
</script>
<h1>User: {user.name}</h1>

3. Declarative Routing:

If you prefer defining routes with components, similar to older versions of React Router, you can use the declarative approach.

<!-- App.svelte -->
<script>
  import { BrowserRouter, Routes, Route } from '@hvniel/svelte-router';
  import Home from './Home.svelte';
  import About from './About.svelte';
</script>
<BrowserRouter>
  <nav>
    <a href="/">Home</a> | <a href="/about">About</a>
  </nav>
  <Routes>
    <Route path="/" Component={Home} />
    <Route path="/about" Component={About} />
  </Routes>
</BrowserRouter>

4. API Methods and Hooks

  • useRevalidator(): Returns a function to revalidate route data, triggering fresh loader execution
  • useNavigate(): Returns a function for programmatic navigation with options for replace, state, and relative navigation
  • useLocation(): Returns the current location object with pathname, search, hash, and state properties
  • useParams(): Returns the current route parameters as a reactive object with proper TypeScript inference
  • useSearchParams(): Returns URL search parameters with methods for reading and updating query strings
  • useHref(to): Returns the href string for a given destination, useful for custom link components
  • useLoaderData<T>(): Returns data from the route loader with full type safety based on loader function return type
  • useActionData<T>(): Returns data from the route action, typically used for form submission results
  • useRouteError(): Returns the current route error for error boundary implementations
  • useNavigation(): Returns navigation state information including loading states and form submission status
  • useSubmit(): Returns a function to submit forms programmatically with full control over submission behavior
  • useFetcher(): Returns a fetcher for loading data without navigation, useful for background data updates

FAQs

Q: Can I use this library with SvelteKit?
A: No, and you shouldn’t try. SvelteKit provides its own powerful, file-based router that is deeply integrated with its lifecycle. This library is designed specifically for client-side SPAs built with Svelte, not SvelteKit.

Q: How do I implement protected routes for authentication?
A: The loader function is the perfect place for this. In your route definition, the loader can check for an authentication status (e.g., from a cookie or local storage). If the user is not authenticated, the loader can throw a redirect() to your login page. This pattern is standard in the React Router world and translates directly here.

Q: What is the main difference between using <Link> and the useNavigate() hook?
A: The <Link> component is for declarative navigation; you render it in your markup like a normal <a> tag for users to click. The useNavigate() hook gives you a function that you can call from your <script> logic to trigger navigation programmatically, such as after a successful form submission or another user event that doesn’t involve clicking a link.

Q: How do I handle authentication and route protection?
A: Route protection works through loader functions that can throw redirect responses or return authentication state. You can implement route guards by checking authentication status in parent route loaders and redirecting unauthenticated users to login pages. The error boundary system also supports displaying authentication-related error messages.

Q: Does this router support server-side rendering?
A: The library includes StaticRouter for server-side rendering scenarios, but it focuses on client-side routing. For comprehensive SSR support with file-based routing and server-side data loading, SvelteKit provides a more complete solution. This router works best for single-page applications that handle SSR through separate backend services.

Q: How do I implement lazy loading for route components?
A: Svelte’s dynamic import syntax works seamlessly with the router. You can use Component: () => import('./LazyComponent.svelte') in your route definitions for data routing mode, or implement lazy loading logic within your route components for declarative routing mode. The router handles loading states through the navigation hook.

Q: Can I use this router for mobile applications built with Capacitor?
A: Yes, the MemoryRouter and HashRouter modes work well in Capacitor environments where browser history might behave differently. The library’s history abstraction handles the differences between web and mobile web view contexts transparently.

Haniel Ubogu

Haniel Ubogu

Frontend Engineer | UI/UX Enthusiast

Leave a Reply

Your email address will not be published. Required fields are marked *