--- name: svelte-best-practices description: Svelte 5 runes, component patterns, stores, transitions, and SvelteKit routing. Use when writing or reviewing Svelte code. --- # Svelte 5 Best Practices ## Runes Only Svelte 5 uses runes. No legacy patterns. **Use:** `$state`, `$derived`, `$effect`, `$props`, `$bindable` **Don't use:** `export let`, `$:`, `on:click`, `writable`, `readable`, `derived` ```svelte ``` ## Component Architecture - One component per file - Props via `$props()` with TypeScript types - Events via callback props (not `createEventDispatcher`) - Slots via `{@render children()}` - Reactive declarations via `$derived`, not `$:` ## Composable Pattern (`createX()`) All stateful logic lives in `.svelte.ts` files using the `createX()` pattern: ```ts export function createCounter(initial = 0) { let count = $state(initial); let doubled = $derived(count * 2); return { get count() { return count; }, get doubled() { return doubled; }, increment() { count++; }, reset() { count = initial; }, }; } ``` Key rules: - Return readonly getters for state - Keep state private inside the closure - Export types alongside the function - Use `.svelte.ts` extension for files containing runes ## Context Pattern Shared state uses `Symbol` keys with centralized factories: ```ts // sidebar-context.svelte.ts const SidebarContext = Symbol('sidebar'); export function setSidebar(state: SidebarState) { setContext(SidebarContext, state); } export function getSidebar(): SidebarState { return getContext(SidebarContext); } ``` ## Reactivity Rules - `$state` for mutable reactive state - `$derived` for computed values (never assign) - `$effect` for side effects (return cleanup function) - `$effect.pre` for effects that need to run before DOM update - `$props()` for component inputs - `$bindable()` for two-way binding props ## SvelteKit Conventions - `+page.svelte` for routes - `+layout.svelte` for shared layout - `+page.server.ts` for server-side data loading - `+error.svelte` for error boundaries - Use `goto()` for programmatic navigation - Use `invalidateAll()` to refresh data ## Testing - `@testing-library/svelte` for component tests - `vitest` for unit tests - Test user interactions, not implementation details - Mock external dependencies (API calls, stores)