--- name: svelte description: Svelte 5 - Reactive UI framework with compiler magic, Runes API, SvelteKit full-stack framework, SSR/SSG, minimal JavaScript version: 1.0.0 category: toolchain author: Claude MPM Team license: MIT progressive_disclosure: entry_point: summary: "Compiler-first reactive UI: $state/$derived/$effect Runes, SvelteKit SSR/SSG, minimal bundle, write less code" when_to_use: "Interactive UIs, dashboards, SPAs, static sites, full-stack apps with performance focus and developer ergonomics" quick_start: "1. npm create svelte@latest 2. Use $state() for reactive state 3. Use $derived() for computed 4. Deploy with adapters" context_limit: 85 tags: - svelte - svelte5 - sveltekit - runes - reactivity - ssr - ssg - compiler - performance - frontend requires_tools: [] --- # Svelte 5 - Compiler-First Reactive Framework ## Overview Svelte is a **compiler-based** reactive UI framework that shifts work from runtime to build time. Unlike React/Vue, Svelte compiles components to highly optimized vanilla JavaScript with minimal overhead. **Svelte 5** introduces Runes API for explicit, fine-grained reactivity. **Key Features**: - **Runes API**: $state, $derived, $effect for explicit reactivity - **Zero runtime overhead**: Compiles to vanilla JS - **Built-in state management**: No external libraries needed - **SvelteKit**: Full-stack framework with SSR/SSG/SPA - **Write less code**: Simple, readable component syntax - **Exceptional performance**: Small bundles, fast runtime **Installation**: ```bash # Create new SvelteKit project npm create svelte@latest my-app cd my-app npm install npm run dev # Or Svelte only (no SvelteKit) npm create vite@latest my-app -- --template svelte-ts ``` ## Svelte 5 Runes API (Modern Approach) ### State Management with $state ```svelte ``` ### Computed Values with $derived ```svelte

{greeting}

Average: {average.toFixed(2)}

``` ### Side Effects with $effect ```svelte ``` ### Component Props with $props ```svelte

{displayTitle}

Count: {count}

``` ### Two-Way Binding with $bindable ```svelte

Found {results.length} results for "{query}"

``` ## Component Patterns ### Basic Component Structure ```svelte
Count: {count} (Doubled: {doubled})
``` ### Conditional Rendering ```svelte {#if loading}

Loading...

{:else if loggedIn && user}

Welcome, {user.name}!

{:else}

Please log in

{/if} ``` ### Lists and Keyed Each Blocks ```svelte ``` ## SvelteKit Framework ### Project Structure ``` my-app/ ├── src/ │ ├── routes/ │ │ ├── +page.svelte # Home page │ │ ├── +page.ts # Universal load │ │ ├── +page.server.ts # Server load │ │ ├── +layout.svelte # Shared layout │ │ ├── about/ │ │ │ └── +page.svelte # /about │ │ └── blog/ │ │ ├── +page.svelte # /blog │ │ └── [slug]/ │ │ └── +page.svelte # /blog/my-post │ ├── lib/ │ │ ├── components/ │ │ ├── stores/ │ │ └── utils/ │ └── app.html ├── static/ # Static assets └── svelte.config.js ``` ### Load Functions (Data Fetching) ```typescript // src/routes/blog/[slug]/+page.ts import type { PageLoad } from './$types'; export const load: PageLoad = async ({ params, fetch }) => { const response = await fetch(`/api/posts/${params.slug}`); const post = await response.json(); return { post }; }; ``` ```svelte

{data.post.title}

{@html data.post.content}
``` ### Server-Only Load Functions ```typescript // src/routes/admin/+page.server.ts import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ locals }) => { if (!locals.user?.isAdmin) { throw redirect(303, '/login'); } const users = await db.users.findMany(); return { users }; }; ``` ### Form Actions ```typescript // src/routes/login/+page.server.ts import { fail, redirect } from '@sveltejs/kit'; import type { Actions } from './$types'; import { z } from 'zod'; const schema = z.object({ email: z.string().email(), password: z.string().min(8) }); export const actions = { default: async ({ request, cookies }) => { const formData = await request.formData(); const data = Object.fromEntries(formData); const result = schema.safeParse(data); if (!result.success) { return fail(400, { errors: result.error.flatten().fieldErrors }); } const user = await authenticateUser(result.data); if (!user) { return fail(401, { message: 'Invalid credentials' }); } cookies.set('session', user.sessionToken, { path: '/' }); throw redirect(303, '/dashboard'); } } satisfies Actions; ``` ```svelte
{#if form?.errors?.email} {form.errors.email[0]} {/if} {#if form?.errors?.password} {form.errors.password[0]} {/if} {#if form?.message}

{form.message}

{/if}
``` ## State Management Patterns ### Runes-Based Store (Modern) ```typescript // src/lib/stores/cart.svelte.ts interface CartItem { id: number; name: string; price: number; quantity: number; } function createCart() { let items = $state([]); let total = $derived( items.reduce((sum, item) => sum + item.price * item.quantity, 0) ); let itemCount = $derived( items.reduce((sum, item) => sum + item.quantity, 0) ); return { get items() { return items; }, get total() { return total; }, get itemCount() { return itemCount; }, addItem(item: Omit) { const existing = items.find(i => i.id === item.id); if (existing) { existing.quantity++; } else { items.push({ ...item, quantity: 1 }); } }, removeItem(id: number) { items = items.filter(i => i.id !== id); }, clear() { items = []; } }; } export const cart = createCart(); ``` ```svelte

Items: {cart.itemCount}

Total: ${cart.total.toFixed(2)}

``` ### Legacy Svelte Store (Svelte 4 Style) ```typescript // src/lib/stores/user.ts import { writable, derived } from 'svelte/store'; interface User { id: number; name: string; email: string; } function createUserStore() { const { subscribe, set, update } = writable(null); return { subscribe, login: (user: User) => set(user), logout: () => set(null), updateName: (name: string) => update(u => u ? { ...u, name } : null) }; } export const user = createUserStore(); // Derived store export const isLoggedIn = derived(user, $user => $user !== null); ``` ```svelte {#if $isLoggedIn}

Welcome, {$user?.name}!

{:else}

Please log in

{/if} ``` ## Animations and Transitions ### Built-in Transitions ```svelte {#if visible}
Fades in and out
Slides in and out
Flies in from bottom
{/if} ``` ### Custom Transitions ```typescript // src/lib/transitions.ts export function blur(node: HTMLElement, { duration = 300 }) { return { duration, css: (t: number) => ` opacity: ${t}; filter: blur(${(1 - t) * 10}px); ` }; } ``` ```svelte {#if show}
Custom blur transition
{/if} ``` ### Animate Directive (FLIP Animations) ```svelte
    {#each items as item (item)}
  • {item}
  • {/each}
``` ## Advanced Features ### Actions (Element Behaviors) ```typescript // src/lib/actions.ts export function clickOutside(node: HTMLElement, callback: () => void) { const handleClick = (event: MouseEvent) => { if (!node.contains(event.target as Node)) { callback(); } }; document.addEventListener('click', handleClick, true); return { destroy() { document.removeEventListener('click', handleClick, true); } }; } ``` ```svelte {#if showMenu} {/if} ``` ### Slots and Component Composition ```svelte
{#if title}

{title}

{:else} Default Header {/if}
Default content

This is the main content

``` ### Special Elements ```svelte Content console.log('Window resized')} onkeydown={(e) => console.log(e.key)} /> My Page ``` ## Migration from React/Vue ### React to Svelte 5 | React | Svelte 5 | Notes | |-------|----------|-------| | `useState(0)` | `$state(0)` | Direct state | | `useMemo(() => x * 2, [x])` | `$derived(x * 2)` | Auto-tracked | | `useEffect(() => {...}, [x])` | `$effect(() => {...})` | Auto deps | | `props.name` | `let { name } = $props()` | Destructure | | `{show &&
}` | `{#if show}
{/if}` | Explicit | ### Vue 3 to Svelte 5 | Vue 3 | Svelte 5 | Notes | |-------|----------|-------| | `ref(0)` | `$state(0)` | Direct state | | `computed(() => x * 2)` | `$derived(x * 2)` | Similar | | `watch(() => x, ...)` | `$effect(() => {...})` | Auto-tracked | | `defineProps<{ name: string }>()` | `let { name } = $props()` | Type-safe | | `v-if="show"` | `{#if show}` | Block syntax | ## Performance Best Practices 1. **Use $derived over $effect** when only computed values are needed 2. **Avoid unnecessary $effect** - only for side effects, not computations 3. **Leverage compiler optimizations** - Svelte does most work at build time 4. **Use keyed each blocks** - `{#each items as item (item.id)}` 5. **Lazy load components** - `const Component = await import('./Heavy.svelte')` 6. **SSR for initial load** - Use SvelteKit's SSR capabilities 7. **Optimize bundles** - Use adapters for deployment targets ## Testing ### Unit Tests with Vitest ```typescript // Counter.test.ts import { render, fireEvent } from '@testing-library/svelte'; import { expect, test } from 'vitest'; import Counter from './Counter.svelte'; test('increments counter on click', async () => { const { getByText } = render(Counter); const button = getByText('+'); await fireEvent.click(button); expect(getByText(/Count: 1/)).toBeInTheDocument(); }); ``` ### E2E with Playwright ```typescript // tests/login.test.ts import { expect, test } from '@playwright/test'; test('user can log in', async ({ page }) => { await page.goto('/login'); await page.fill('input[name="email"]', 'user@example.com'); await page.fill('input[name="password"]', 'password123'); await page.click('button[type="submit"]'); await expect(page).toHaveURL('/dashboard'); await expect(page.locator('text=Welcome')).toBeVisible(); }); ``` ## Deployment ### Adapters ```javascript // svelte.config.js import adapter from '@sveltejs/adapter-vercel'; // or adapter-node, adapter-static export default { kit: { adapter: adapter() } }; ``` **Available Adapters**: - `adapter-auto`: Auto-detect platform - `adapter-vercel`: Vercel deployment - `adapter-node`: Node.js server - `adapter-static`: Static site generation - `adapter-cloudflare`: Cloudflare Pages/Workers - `adapter-netlify`: Netlify deployment ## Resources - **Svelte Docs**: https://svelte.dev/docs - **SvelteKit Docs**: https://kit.svelte.dev/docs - **Svelte 5 Runes**: https://svelte-5-preview.vercel.app/docs/runes - **Tutorial**: https://learn.svelte.dev - **REPL**: https://svelte.dev/repl ## Summary - **Svelte 5** uses Runes API ($state, $derived, $effect) for explicit reactivity - **Compiler-first** - shifts work to build time for minimal runtime overhead - **SvelteKit** provides full-stack capabilities with SSR/SSG/SPA modes - **Write less code** - simpler syntax than React/Vue - **Exceptional performance** - small bundles, fast runtime - **Migration-friendly** - Svelte 4 and 5 can coexist - **Type-safe** - First-class TypeScript support