State in the URL

+15 Mana ✨

For state that should be shareable or bookmarkable, put it in the URL.

Reading URL State

javascript
// +page.server.js
export async function load({ url }) {
  const page = Number(url.searchParams.get('page') ?? 1);
  const search = url.searchParams.get('q') ?? '';
  const sort = url.searchParams.get('sort') ?? 'date';
  
  const products = await getProducts({ page, search, sort });
  
  return { products, page, search, sort };
}
svelte
<!-- +page.svelte -->
<script>
  let { data } = $props();
</script>

<p>Showing results for "{data.search}"</p>

Updating URL State

svelte
<script>
  import { goto } from '$app/navigation';
  import { page } from '$app/stores';
  
  let { data } = $props();
  
  function updateSearch(newSearch) {
    const url = new URL($page.url);
    url.searchParams.set('q', newSearch);
    url.searchParams.set('page', '1'); // Reset to page 1
    goto(url);
  }
  
  function changePage(newPage) {
    const url = new URL($page.url);
    url.searchParams.set('page', String(newPage));
    goto(url);
  }
</script>

<input 
  value={data.search} 
  onchange={(e) => updateSearch(e.currentTarget.value)}
/>

<button onclick={() => changePage(data.page + 1)}>Next Page</button>

For simple cases, regular links work:

svelte
<script>
  let { data } = $props();
  import { page } from '$app/stores';
</script>

<nav class="pagination">
  {#each Array(data.totalPages) as _, i}
    <a 
      href="?page={i + 1}" 
      class:active={$page.url.searchParams.get('page') == i + 1}
    >
      {i + 1}
    </a>
  {/each}
</nav>

goto() Options

javascript
import { goto } from '$app/navigation';

// Replace history entry (no back button entry)
goto(url, { replaceState: true });

// Keep scroll position
goto(url, { noScroll: true });

// Prevent load function from re-running
goto(url, { invalidateAll: false });

šŸ“– Navigation documentation

āœ“ Completed