When users navigate away and come back, local component state is lost:
svelte<script> // User types a comment... let comment = $state(''); </script> <!-- User navigates away, comes back --> <!-- comment is now '' again! --> <textarea bind:value={comment}></textarea>
The Solution: Snapshots
SvelteKit's snapshot feature preserves and restores state:
svelte<!-- +page.svelte --> <script> let comment = $state(''); let scrollPosition = $state(0); export const snapshot = { capture: () => ({ comment, scrollPosition: window.scrollY }), restore: (value) => { comment = value.comment; // Restore scroll after render tick().then(() => window.scrollTo(0, value.scrollPosition)); } }; </script> <textarea bind:value={comment}></textarea>
How Snapshots Work
- User navigates away →
capture()saves state - User clicks back →
restore()receives saved state - State is stored in browser history (survives refresh!)
What to Snapshot
Good candidates:
- Form inputs (drafts, unsaved data)
- Scroll position
- Expanded/collapsed sections
- Filter/sort selections NOT in URL
- Tab selections
Don't snapshot:
- Data that should be in URL (filters, pagination)
- Authentication state
- Large data (there are size limits)
Complex Snapshot Example
svelte<script> import { tick } from 'svelte'; let formData = $state({ title: '', body: '', tags: [] }); let activeTab = $state('write'); let expandedSections = $state(new Set()); export const snapshot = { capture: () => ({ formData: { ...formData }, activeTab, expandedSections: [...expandedSections], scroll: window.scrollY }), restore: (value) => { formData = value.formData; activeTab = value.activeTab; expandedSections = new Set(value.expandedSections); tick().then(() => window.scrollTo(0, value.scroll)); } }; </script>