Svelte and SvelteKit course Β· Module 11: SvelteKit Routing

Dynamic Routes and Parameters

1 min read Β·
In this lesson4

Dynamic segments [param]

src/routes/warriors/[id]/+page.svelte
<!-- src/routes/warriors/[id]/+page.svelte -->
<script>
  let { data } = $props();
</script>

<h1>Warrior: {data.warrior.name}</h1>
<p>Strength: {data.warrior.strength}</p>

Whatever the load function returns reaches the page as the data prop. You receive it with $props(), like any other prop in Svelte 5.

// src/routes/warriors/[id]/+page.js
export function load({ params }) {
  const warriors = [
    { id: '1', name: 'Ragnar', strength: 95 },
    { id: '2', name: 'Bjorn', strength: 88 }
  ];

  const warrior = warriors.find(w => w.id === params.id);

  return { warrior };
}

Rest parameters [...slug]

src/routes/docs/[...path]/+page.svelte

Matches: /docs/a, /docs/a/b, /docs/a/b/c

// +page.js
export function load({ params }) {
  // params.path = 'a/b/c'
  const segments = params.path.split('/');
  return { segments };
}

Optional parameters [[param]]

src/routes/warriors/[[page]]/+page.svelte

Matches: /warriors, /warriors/2

Route grouping (groups)

src/routes/
β”œβ”€β”€ (public)/
β”‚   β”œβ”€β”€ about/+page.svelte    # /about
β”‚   └── contact/+page.svelte  # /contact
β”œβ”€β”€ (auth)/
β”‚   β”œβ”€β”€ login/+page.svelte    # /login
β”‚   └── register/+page.svelte # /register
└── (app)/
    └── dashboard/+page.svelte # /dashboard

Groups (in parentheses) don't affect the URL!

Code for this lesson: App.svelte
<script>
  // Dynamic parameters and query strings

  let warriorId = $state('ragnar');
  let sortBy = $state('name');
  let filter = $state('all');

  // Data simulation
  const warriors = {
    ragnar: { name: 'Ragnar Lothbrok', strength: 95, clan: 'Lothbrok' },
    bjorn: { name: 'Bjorn Ironside', strength: 90, clan: 'Lothbrok' },
    ivar: { name: 'Ivar the Boneless', strength: 85, clan: 'Lothbrok' }
  };

  let currentWarrior = $derived(warriors[warriorId]);
  let queryString = $derived(`?sort=${sortBy}&filter=${filter}`);
</script>

<main class="params-demo">
  <h1>Parametry URL</h1>

  <section>
    <h2>Dynamic parameter [id]</h2>
    <p class="path">/warriors/<strong>[id]</strong></p>

    <div class="options">
      {#each Object.keys(warriors) as id}
        <button
          class:active={warriorId === id}
          onclick={() => warriorId = id}
        >
          {id}
        </button>
      {/each}
    </div>

    {#if currentWarrior}
      <div class="warrior-info">
        <h3>{currentWarrior.name}</h3>
        <p>Strength: {currentWarrior.strength}</p>
        <p>Clan: {currentWarrior.clan}</p>
      </div>
    {/if}

    <pre>
// +page.server.js
export function load({"{"} params {"}"}) {"{"}
  const warrior = getWarrior(params.id);
  return {"{"} warrior {"}"};
{"}"}
    </pre>
  </section>

  <section>
    <h2>Query strings</h2>
    <p class="path">/warriors<strong>{queryString}</strong></p>

    <div class="controls">
      <label>
        Sort by:
        <select bind:value={sortBy}>
          <option value="name">Name</option>
          <option value="strength">Strength</option>
        </select>
      </label>

      <label>
        Filter:
        <select bind:value={filter}>
          <option value="all">All</option>
          <option value="alive">Alive</option>
          <option value="dead">Dead</option>
        </select>
      </label>
    </div>

    <pre>
// +page.server.js
export function load({"{"} url {"}"}) {"{"}
  const sort = url.searchParams.get('sort');
  const filter = url.searchParams.get('filter');
  return {"{"} sort, filter {"}"};
{"}"}
    </pre>
  </section>
</main>

<style>
  .params-demo {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: #0a1628;
    color: #b8d4f7;
    min-height: 100vh;
  }

  h1 {
    color: #4a90d9;
    text-align: center;
  }

  section {
    background: rgba(74, 144, 217, 0.1);
    border: 1px solid #4a90d9;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #4a90d9;
    font-size: 1rem;
    margin-top: 0;
  }

  .path {
    font-family: monospace;
    background: rgba(0,0,0,0.5);
    padding: 0.5rem 1rem;
    border-radius: 4px;
  }

  .path strong {
    color: #ffd700;
  }

  .options {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0;
  }

  button {
    padding: 0.5rem 1rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
    cursor: pointer;
  }

  button.active {
    background: #4a90d9;
    color: #0a1628;
  }

  .warrior-info {
    background: rgba(0,0,0,0.3);
    padding: 1rem;
    border-radius: 4px;
    margin: 1rem 0;
  }

  .warrior-info h3 {
    color: #ffd700;
    margin: 0 0 0.5rem 0;
  }

  .controls {
    display: flex;
    gap: 1rem;
    margin: 1rem 0;
  }

  label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }

  select {
    padding: 0.5rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
  }

  pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.8rem;
    overflow-x: auto;
  }
</style>

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How do you create a dynamic route for /warriors/123?

Useful articles