Claude
Skills
Sign in
Back

svelte

Included with Lifetime
$97 forever

Svelte runes-first reactivity and SvelteKit fullstack conventions. Invoke whenever task involves any interaction with Svelte code — writing, reviewing, refactoring, debugging, or understanding .svelte, .svelte.js, .svelte.ts files and SvelteKit projects.

Web Dev

What this skill does


# Svelte

**Reactivity is explicit, compiler-driven, and minimal-runtime.** Every reactive declaration uses a `$` rune. The
compiler transforms declarative code into surgical DOM updates -- no virtual DOM, no diffing, no hidden magic.
References contain extended examples, rationale, and edge cases for each topic.

## References

- **Runes** — [`${CLAUDE_SKILL_DIR}/references/runes.md`]: `$state`, `$derived`, `$effect`, `$props`, `$bindable`
  details
- **Components** — [`${CLAUDE_SKILL_DIR}/references/components.md`]: Snippets, events, context, special elements
- **SvelteKit** — [`${CLAUDE_SKILL_DIR}/references/sveltekit.md`]: Routing, load functions, form actions, hooks, imports

## Runes

### `$state`

- Every mutable reactive value must use `$state` or `$state.raw`. Plain `let` declarations are not reactive.
- Arrays and plain objects become deeply reactive proxies. Mutations trigger granular updates.
- Destructuring `$state` objects breaks reactivity -- destructured values are snapshots, not live references.
- Use `$state` on class fields or as first assignment in constructor. The compiler transforms these into getter/setter
  pairs. Use arrow functions to preserve `this` in event handlers on classes.
- `$state.raw` opts out of deep reactivity -- state can only be reassigned, not mutated. Use for large arrays/objects
  you replace wholesale to avoid proxy overhead.
- `$state.snapshot(value)` takes a static copy of a reactive proxy for external APIs that don't expect proxies (e.g.,
  `structuredClone`, logging).
- Import reactive `Set`, `Map`, `Date`, `URL` from `svelte/reactivity` when you need reactive built-in types.

### Sharing State Across Modules

Cannot directly export reassignable `$state`. Two patterns:

- **Object property (preferred):** export `$state({ count: 0 })` as a const, mutate properties, export modifier
  functions.
- **Getter function:** keep `$state` private, export `getCount()` and `increment()`.

Runes only work in `.svelte` and `.svelte.js`/`.svelte.ts` files.

### `$derived`

- Use `$derived` for all computed values -- never synchronize state with `$effect`.
- `$derived.by(() => { ... })` for complex derivations needing a function body.
- Only synchronously read values are tracked. Use `untrack` to exempt specific reads.
- Derived values can be temporarily overridden (useful for optimistic UI) -- reverts to derived computation on next
  dependency update.
- Destructured `$derived` values are individually reactive.
- Push-pull reactivity: dependents are notified immediately (push) but only recalculated on read (pull). If new value is
  referentially identical, downstream updates are skipped.

### `$effect`

- `$effect` is an escape hatch. Use only for side effects: DOM manipulation, analytics, third-party library calls,
  timers.
- Return a cleanup function when acquiring resources (intervals, listeners).
- Only synchronously read values are tracked -- values read after `await` or inside `setTimeout` are NOT tracked.
- Conditional reads: only values read in the last execution are dependencies.
- Runs only in the browser, after DOM updates.
- `$effect.pre` runs before DOM updates -- use for pre-DOM manipulation like autoscrolling.
- `$effect.tracking()` returns `true` if code is running inside a tracking context.
- `$effect.root(() => { ... })` creates a non-tracked scope for manual effect lifecycle control. Returns a destroy
  function.

**Never use `$effect` to synchronize state** -- use `$derived` with callback event handlers or function bindings
instead.

### `$props`

- Always destructure props: `let { name, count = 0 } = $props()`.
- Type with an interface in TypeScript: `let { name }: Props = $props()`.
- Renaming: `let { class: klass } = $props()`.
- Rest props: `let { a, b, ...rest } = $props()`.
- All props: `let props = $props()`.
- Unique ID: `$props.id()` -- consistent across SSR/hydration.
- Props can be temporarily overridden by child. Do NOT mutate prop objects unless `$bindable`. Use callback props to
  communicate changes upward.

### `$bindable`

- Marks a prop as two-way bindable: `let { value = $bindable() } = $props()`.
- Parent optionally uses `bind:value={variable}`.
- Use sparingly -- overuse makes data flow unpredictable. Prefer callback props for most parent-child communication.

### `$inspect`

- Development-only debugging rune. Re-runs when arguments change. Noop in production.
- `$inspect(count, message)` logs when tracked values change.
- `$inspect(value).with((type, ...args) => { ... })` replaces default `console.log` with custom callback. Type is
  `"init"` or `"update"`.
- `$inspect.trace()` traces which reactive state caused a re-execution. Must be first statement in a function body.

### `$host`

Only available inside custom elements. Provides access to the host element for dispatching custom events.

## Components

### Structure Order

1. Imports
2. Props (`$props()`)
3. State (`$state`)
4. Derived values (`$derived`)
5. Effects (`$effect`, sparingly)
6. Functions
7. Markup (template)
8. Styles (`<style>`)

### Naming

- Capitalize component names: `<MyComponent />`. Required for dynamic rendering.
- Component names must be capitalized or use dot notation (`item.component`).
- Components are dynamic by default -- `<svelte:component>` is unnecessary. Just use `<Thing />` where `Thing` is a
  reactive variable.

### Events

- Use standard event attributes: `onclick={handler}`, never `on:click={handler}`.
- Event attributes are case sensitive -- `onclick` listens to `click`, `onClick` listens to `Click`.
- No event modifiers -- call `event.preventDefault()` / `event.stopPropagation()` in the handler. For capture, append to
  event name: `onclickcapture={...}`.
- Callback props for component events -- pass functions as props: `let { onEvent } = $props()`. Never use
  `createEventDispatcher`.
- Event forwarding: accept callback props and spread them onto elements.
- Multiple handlers: combine in a single function (no duplicate attributes).
- Svelte uses event delegation for common events (`click`, `input`, `keydown`) -- single listener at app root. When
  manually dispatching events, set `{ bubbles: true }`. Prefer `on` from `svelte/events` over raw `addEventListener`.

### Snippets

- Use `{@render children?.()}` for default content. Never use `<slot />`.
- Named snippets: declare with `{#snippet header()}...{/snippet}` in parent, accept as props, render with
  `{@render header()}`.
- Snippets with parameters pass data from child to parent: `{@render item(entry)}` in child, `{#snippet item(text)}` in
  parent.
- Optional snippets: use `{@render children?.()}` or `{#if children}` with fallback.
- Snippets follow lexical scoping -- visible within their declaring block and children.
- Top-level snippets can be exported from `<script module>` for cross-component use.
- Type snippets with `Snippet` and `Snippet<[ParamType]>` from `svelte`.

### Template Syntax

**Control flow:**

- `{#if}` / `{:else if}` / `{:else}` / `{/if}` for conditional blocks.
- `{#each items as item, index (item.id)}` with key expression for lists. Always provide a key for lists that can
  change. `:else` renders when array is empty.
- `{#key value}` destroys and recreates contents when value changes -- triggers entry transitions or resets component
  state.
- `{#await promise}` / `{:then value}` / `{:catch error}` for async. Short forms: `{#await promise then value}` skips
  loading state.

**Special tags:**

- `{@html rawHtml}` -- render raw HTML (escape user input to prevent XSS).
- `{@const x = expr}` -- declare local constant inside a block scope.
- `{@debug var1, var2}` -- trigger debugger when values change.
- `{@render snippet()}` -- render a snippet.
- `{@attach action}` -- attach an action to an element.

**Text expressions:** `{expression}` outputs stringified, escaped value. `null` and `undefined` are omitted.

**Conditional classes:** object syntax like `clsx`: `class={{ cool, lame: !cool }}`.

### Context
Files: 5
Size: 43.2 KB
Complexity: 47/100
Category: Web Dev

Related in Web Dev