--- name: svelte description: This skill should be used when working with Svelte 3/4, including components, reactivity, stores, lifecycle, and component communication. Provides comprehensive knowledge of Svelte patterns, best practices, and reactive programming concepts. --- # Svelte 3/4 Skill This skill provides comprehensive knowledge and patterns for working with Svelte effectively in modern web applications. ## When to Use This Skill Use this skill when: - Building Svelte applications and components - Working with Svelte reactivity and stores - Implementing component communication patterns - Managing component lifecycle - Optimizing Svelte application performance - Troubleshooting Svelte-specific issues - Working with Svelte transitions and animations - Integrating with external libraries ## Core Concepts ### Svelte Overview Svelte is a compiler-based frontend framework that: - **Compiles to vanilla JavaScript** - No runtime library shipped to browser - **Reactive by default** - Variables are reactive, assignments trigger updates - **Component-based** - Single-file components with `.svelte` extension - **CSS scoping** - Styles are scoped to components by default - **Built-in transitions** - Animation primitives included - **Two-way binding** - Simple data binding with `bind:` ### Component Structure Svelte components have three sections: ```svelte ``` ## Reactivity ### Reactive Declarations Use `$:` for reactive statements and computed values: ```svelte ``` ### Reactive Assignments Reactivity is triggered by assignments: ```svelte ``` **Key Points:** - Array methods like `push`, `pop` need reassignment to trigger updates - Object property changes need reassignment - Use spread operator for immutable updates ## Props ### Declaring Props ```svelte

{greeting}, {name}!

``` ### Spread Props ```svelte ``` ### Prop Types with JSDoc ```svelte ``` ## Events ### DOM Events ```svelte ``` ### Component Events Dispatch custom events from components: ```svelte ``` ```svelte ``` ### Event Forwarding ```svelte ``` ## Bindings ### Two-Way Binding ```svelte A B ``` ### Component Bindings ```svelte ``` ### Element Bindings ```svelte
{divWidth} x {divHeight}
``` ## Stores ### Writable Stores ```javascript // stores.js import { writable } from 'svelte/store'; export const count = writable(0); // With custom methods function createCounter() { const { subscribe, set, update } = writable(0); return { subscribe, increment: () => update(n => n + 1), decrement: () => update(n => n - 1), reset: () => set(0) }; } export const counter = createCounter(); ``` ```svelte

Count: {$count}

Counter: {$counter}

``` ### Readable Stores ```javascript import { readable } from 'svelte/store'; // Time store that updates every second export const time = readable(new Date(), function start(set) { const interval = setInterval(() => { set(new Date()); }, 1000); return function stop() { clearInterval(interval); }; }); ``` ### Derived Stores ```javascript import { derived } from 'svelte/store'; import { time } from './stores.js'; export const elapsed = derived( time, $time => Math.round(($time - start) / 1000) ); // Derived from multiple stores export const combined = derived( [storeA, storeB], ([$a, $b]) => $a + $b ); // Async derived export const asyncDerived = derived( source, ($source, set) => { fetch(`/api/${$source}`) .then(r => r.json()) .then(set); }, 'loading...' // initial value ); ``` ### Store Contract Any object with a `subscribe` method is a store: ```javascript // Custom store implementation function createCustomStore(initial) { let value = initial; const subscribers = new Set(); return { subscribe(fn) { subscribers.add(fn); fn(value); return () => subscribers.delete(fn); }, set(newValue) { value = newValue; subscribers.forEach(fn => fn(value)); } }; } ``` ## Lifecycle ### Lifecycle Functions ```svelte ``` **Key Points:** - `onMount` runs only in browser, not during SSR - `onMount` callbacks must be called during component initialization - Use `tick()` to wait for pending state changes to apply to DOM ## Logic Blocks ### If Blocks ```svelte {#if condition}

Condition is true

{:else if otherCondition}

Other condition is true

{:else}

Neither condition is true

{/if} ``` ### Each Blocks ```svelte {#each items as item}
  • {item.name}
  • {/each} {#each items as item, index}
  • {index}: {item.name}
  • {/each} {#each items as item (item.id)}
  • {item.name}
  • {/each} {#each items as { id, name }}
  • {id}: {name}
  • {/each} {#each items as item}
  • {item.name}
  • {:else}

    No items

    {/each} ``` ### Await Blocks ```svelte {#await promise}

    Loading...

    {:then value}

    The value is {value}

    {:catch error}

    Error: {error.message}

    {/await} {#await promise then value}

    The value is {value}

    {/await} ``` ### Key Blocks Force component recreation when value changes: ```svelte {#key value} {/key} ``` ## Slots ### Basic Slots ```svelte

    No content provided

    ``` ```svelte

    Card content

    ``` ### Named Slots ```svelte
    ``` ```svelte

    Page Title

    Main content

    Footer content

    ``` ### Slot Props ```svelte
      {#each items as item}
    • {item.name}
    • {/each}
    ``` ```svelte {index}: {item.name} ``` ## Transitions and Animations ### Transitions ```svelte {#if visible}
    Fades in and out
    {/if} {#if visible}
    Flies in
    {/if} {#if visible}
    Different transitions
    {/if} {#if visible}
    Slides with easing
    {/if} ``` ### Custom Transitions ```javascript function typewriter(node, { speed = 1 }) { const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE; if (!valid) { throw new Error('This transition only works on text nodes'); } const text = node.textContent; const duration = text.length / (speed * 0.01); return { duration, tick: t => { const i = Math.trunc(text.length * t); node.textContent = text.slice(0, i); } }; } ``` ### Animations Animate elements when they move within an each block: ```svelte {#each items as item (item.id)}
  • {item.name}
  • {/each} ``` ## Actions Reusable element-level logic: ```svelte
    visible = false}> Click outside to close
    ``` ## Special Elements ### svelte:component Dynamic component rendering: ```svelte ``` ### svelte:element Dynamic HTML elements: ```svelte Dynamic heading ``` ### svelte:window ```svelte ``` ### svelte:body and svelte:head ```svelte Page Title ``` ### svelte:options ```svelte ``` ## Context API Share data between components without prop drilling: ```svelte ``` ```svelte

    Current theme: {theme.color}

    ``` **Key Points:** - Context is not reactive by default - Use stores in context for reactive values - Context is available only during component initialization ## Best Practices ### Component Design 1. **Keep components focused** - Single responsibility 2. **Use composition** - Prefer slots over complex props 3. **Extract logic to stores** - Shared state in stores 4. **Use actions for DOM logic** - Reusable element behaviors 5. **Type with JSDoc** - Document prop types ### Reactivity 1. **Understand triggers** - Assignments trigger updates 2. **Use immutable patterns** - Spread for arrays/objects 3. **Avoid side effects in reactive statements** - Keep them pure 4. **Use derived stores** - For computed values from stores ### Performance 1. **Key each blocks** - Use unique keys for list items 2. **Use immutable option** - When data is immutable 3. **Lazy load components** - Dynamic imports 4. **Minimize store subscriptions** - Unsubscribe when done ### State Management 1. **Local state first** - Component variables for local state 2. **Stores for shared state** - Cross-component communication 3. **Context for configuration** - Theme, i18n, etc. 4. **Custom stores for logic** - Encapsulate complex state ## Common Patterns ### Async Data Loading ```svelte {#if loading}

    Loading...

    {:else if error}

    Error: {error.message}

    {:else}

    {data}

    {/if} ``` ### Form Handling ```svelte
    {#if errors.name}{errors.name}{/if} {#if errors.email}{errors.email}{/if}
    ``` ### Modal Pattern ```svelte {#if open}
    {/if} ``` ## Troubleshooting ### Common Issues **Reactivity not working:** - Check for proper assignment (reassign arrays/objects) - Use `$:` for derived values - Store subscriptions need `$` prefix **Component not updating:** - Verify prop changes trigger parent re-render - Check key blocks for forced recreation - Use `{#key}` to force component recreation **Memory leaks:** - Clean up subscriptions in `onDestroy` - Return cleanup functions from `onMount` - Unsubscribe from stores manually if not using `$` **Styles not applying:** - Check for `:global()` if targeting child components - Verify CSS specificity - Use `class:` directive properly ## References - **Svelte Documentation**: https://svelte.dev/docs - **Svelte Tutorial**: https://svelte.dev/tutorial - **Svelte REPL**: https://svelte.dev/repl - **Svelte Society**: https://sveltesociety.dev - **GitHub**: https://github.com/sveltejs/svelte ## Related Skills - **rollup** - Bundling Svelte applications - **nostr-tools** - Nostr integration in Svelte apps - **typescript** - TypeScript with Svelte