SvelteKit Shallow Routing: pushState & Modal State Sync
- Last updated
- Prerequisites:
- SvelteKit navigation basics
- Understanding of the History API
- sveltekit
- shallow-routing
- pushstate
- modals
- url
- navigation
Read at your depth
The practical view
Shallow routing updates the URL without running load functions or triggering a navigation. In SvelteKit: import { pushState } from '$app/navigation'; pushState(url, state);. This changes the address bar and adds a history entry, but does NOT call load, so no data is re-fetched and no component re-renders from the router. Use it for modal/drawer state that you want reflected in the URL (shareable, back-button-closable) without a real page change. To close: pushState back to the original URL, or use the browser's back button (the history entry exists). Read the state via $page.url or $page.state.
The same idea in other frameworks
React Router's history.pushState and URL-search-param state patterns mirror shallow routing.Angular's Location.go / Router without navigation events approximates it.Vue Router's router.replace with same-route params is the analogue.SvelteKit pushState — the current topic.Legacy vs modern
Full navigation for a modal vs shallow routing
Navigating to a modal URL re-runs load and recreates the page; shallow routing updates only the URL/state, keeping the page and data intact.
await goto('/photos/1'); // ❌ OLD: full navigation — load runs, page re-renderspushState(new URL('/photos/1', location.href), { modal: 'photo' }); // ✅ NEWInterview gotchas
Context
This tests the navigation pipeline distinction — interviewers want you to enumerate what a full navigation triggers (load, component swap) and why shallow routing avoids each for ephemeral UI state.
The mechanical answer
goto (full navigation) runs the navigation pipeline: it resolves the new route, calls its load functions (fetching data), potentially invokes guards, swaps the component tree, and updates the document. pushState bypasses all of that: it only calls history.pushState, updates the $page url/state, and leaves the current component and its data untouched. For a modal, that is exactly right — the overlay is UI state layered on the current page, not a new page. Full navigation would unmount the list, re-fetch data on return, and lose scroll position. Shallow routing also makes the modal's state part of the URL: refresh restores the URL (and you can re-open the modal from it), and the back button naturally closes it because the previous history entry is the closed state.
Trap
The naive answer is 'pushState is just a faster goto'. It does not run load at all — that's a semantic difference, not a speed one. Another trap: expecting the new URL to reflect server state or trigger data updates — it won't, and code that relies on load running will silently keep stale data. Candidates who enumerate the skipped pipeline steps show real understanding.
Context
This probes the state-recovery pattern — interviewers want to know how the URL becomes the source of truth for ephemeral UI after a page reload, which is the point of URL-syncing modals.
The mechanical answer
On refresh, the URL is the only thing that survives — the in-memory modal state is gone. To restore, your page reads $page.url (and $page.state) during initialization: if the URL path/query indicates a modal (e.g. /photos/1), re-open the modal and load its content. The state argument passed to pushState is stored on the history entry and available via $page.state after back/forward navigation, but on a hard refresh the state object is NOT restored (only the URL is) — so recovery must be driven primarily from the URL, with $page.state as supplementary ephemeral data. The robust pattern: derive modal-openness from the URL, not from component state alone, so refresh, share, and back-button all behave consistently.
Trap
The naive answer is '$page.state survives a refresh'. History state does not survive a full page reload — only the URL does. Another trap: storing non-serializable data in the state argument — the History API requires structured-cloneable values. Candidates who center recovery on the URL and treat state as ephemeral show real production experience.