Before diving into implementation, let's understand the different types of state in a web application and where each belongs.
1. UI State (Local)
State that only matters to a single component:
svelte<script> // UI-only state - stays local let isDropdownOpen = $state(false); let selectedTab = $state('details'); let inputValue = $state(''); </script>
Examples:
- Whether a dropdown/modal is open
- Current tab selection
- Form input values (before submission)
- Hover/focus states
- Animation states
2. Shared UI State
State that multiple components need to read or modify:
svelte<script> // Multiple components need this // Could be lifted to parent, or use Context/stores let notifications = $state([]); let sidebarCollapsed = $state(false); </script>
Examples:
- Toast notifications
- Sidebar open/closed
- Theme (light/dark)
- Modal visibility controlled from multiple places
3. Server/Cache State
Data fetched from APIs that needs to be cached and synchronized:
svelte<script> // Server state - best handled by specialized libraries // Like TanStack Query, SWR, or SvelteKit's load functions let user = $state(null); let products = $state([]); </script>
Examples:
- User profile data
- Product listings
- Comments, posts
- Any API response
4. URL State
State that lives in the URL and should be shareable:
/products?category=electronics&sort=price&page=2
Examples:
- Filters and search queries
- Pagination
- Selected items
- Feature flags
The Golden Rule
Start with the simplest solution that works:
- Local state (
$statein component) - Start here - Lifted state (props from parent) - When siblings need to share
- Context (
setContext/getContext) - For deeply nested trees - Global stores (
.svelte.jsfiles) - For truly app-wide state - External libraries - For complex server state