Svelte

Store Integration

Curi's Svelte integration relies on stores and context. These are setup automatically if you pass a Curi router to the Router component.

import App from "./components/App.svelte";

const router = createRouter(browser, routes);
new App({ target, props: { router } });

The Router component makes router related data available throughout the application.

<!-- /components/App.svelte -->
<Router {router}>
  <Content />
</Router>

<script>
  import Router from "@curi/svelte/components/Router.svelte";
  import Content from "./components/Content.svelte";

  export let router;
</script>

Components that need to access the router, response, or navigation can do so with their corresponding getter functions.

<script>
  import { getRouter, getResponse, getNavigation } from "@curi/svelte";

  const router = getRouter();
  const response = getResponse();
  const navigation = getNavigation();
</script>

The getRouter function returns the actual router, while getResponse and getNavigation return stores that update whenever the application navigates.

Rendering with the response

Svelte allows you to render dynamic components using the <svelte:component this> syntax. If you set Svelte components as the body properties on your responses, you can combine <svelte:component this> and response.body to render the appropriate component for a response.

A root component is a good place to perform general application layout, like menus, in addition to rendering the response's body.

<!-- components/Content.svelte -->
<template>
  <header>
    <NavLinks />
  </header>
  <main>
    <svelte:component this={$response.body} />
  </main>
</template>

<script>
  import { getResponse } from "@curi/svelte";
  import NavLinks from "./NavLinks";

  const response = getResponse();
</script>

If your routes use an object to attach multiple components to a response, splitting them apart in computed properties may give your templates a cleaner look.

If you do attach multiple components to a response, please remember that you want every route to set the same body shape. Otherwise, you'll have to determine the shape and change how you render, which can quickly become messy.

const routes = prepareRoutes([
  {
    name: "Home",
    path: "",
    respond() {
      return {
        body: {
          main: HomeMain,
          menu: HomeMenu
        }
      }
    }
  },
  // ...
]);
<header>
  <svelte:component this={menu} />
</header>
<main>
  <svelte:component this={main} />
</main>

<script>
  import { getResponse } from "@curi/svelte";

  const response = getResponse();
  $: main = $response.body.main;
  $: menu = $response.body.menu;
</script>

The Link component is used to navigate between routes within an application. When it renders in the DOM, it will render as an anchor (<a>) element.

The Link's name prop describes which route clicking the link should navigate to. If you pass an invalid route name, Curi will warn you.

If a route has any params (or if any of a route's ancestors have params for nested routes), the params prop is used to pass these to the Link.

<template>
  <nav>
    <ul>
      <li>
        <Link name="Home">Home</Link>
      </li>
      <li>
        <Link name="About">About</Link>
      </li>
      <li>
        <Link name="User" params={{ id: 'blue' }}>
          Blue
        </Link>
      </li>
    </ul>
  </nav>
</template>

<script>
  import Link from "@curi/svelte/components/Link.svelte";
</script>

The Link also takes hash, query, and state props to attach their values to the location that will be navigated to.

<Link name="Home" hash="details">Home</Link>
// renders
<a href="/#details">Home</a>

Please check out the full @curi/svelte API documentation to see every component that the package provides.

  1. Store Integration
    1. Rendering with the response
  2. Navigating