| name | svelte |
| description | Svelte 5 component and state-module patterns for Epicenter apps. Use when editing `.svelte`, `.svelte.ts`, or Svelte UI state code involving runes, `$props`, snippets, keyed lifecycles, `{#await}`, TanStack Query, `SvelteMap`/`SvelteSet`, `createSubscriber`, `$state.raw`, shadcn-svelte, or workspace observers. |
Svelte Guidelines
Keep the first pass focused on Svelte runes, component lifecycle, workspace-backed state, TanStack Query usage, and local UI composition.
Reference Repositories
- Svelte: Svelte 5 framework with runes and fine-grained reactivity
- shadcn-svelte: Port of shadcn/ui for Svelte with Bits UI primitives
- shadcn-svelte-extras: Additional components for shadcn-svelte
Source Checks
- Check Svelte
$props, $bindable, and snippets before changing prop ownership, bind: APIs, or children snippet typing rules.
- Check Svelte
{#key}, {#await}, and lifecycle hooks before changing keyed resource or async readiness guidance.
- Check Svelte
{@attach}, use:, and svelte/attachments before changing reusable DOM behavior, actions, or attachment guidance.
- Check Svelte
svelte/reactivity before changing SvelteMap, SvelteSet, or reactive collection guidance.
- Check the Svelte 5 migration guide before changing legacy API avoidance, event syntax, slot migration, or callback-prop guidance.
- Check TanStack Svelte Query
createMutation and local installed types before changing mutation lifecycle guidance.
Upstream Grounding
When Svelte 5 runes, compiler behavior, lifecycle, reactivity, snippets, or template behavior affect correctness, use source-backed grounding before relying on memory. If DeepWiki MCP is available, ask a narrow question against sveltejs/svelte; for SvelteKit integration, ask against sveltejs/kit; for shadcn-svelte or extras component APIs, ask against huntabyte/shadcn-svelte or ieedan/shadcn-svelte-extras. If DeepWiki is unavailable or the repo is not indexed, use upstream source or official docs directly. Treat DeepWiki as orientation, then verify decisive details against local installed types, source, or official docs before changing code.
Skip DeepWiki for stable basics and repo-local patterns already documented here or in references.
Related Skills
query-layer: TanStack Query integration
error-handling: $lib/report, extractErrorMessage, and component error handling
styling: CSS and Tailwind conventions, including the flex column scroll trap
ui-design: visual direction plus loading, empty, pending, tooltip, and component selection patterns
Svelte 5 Baseline
- Use
$state for reactive values the component mutates in place. Use $state.raw for values that are only ever reassigned wholesale (large arrays, replace-only persisted stores, opaque handles): it stores by reference with no deep proxy, does not freeze, and reacts only to reassignment, so an in-place property write mutates the object without triggering reactivity or persistence (not an error, but not reactive either). Reach for it when the deep proxy buys reactivity you never use, and when stable value identity matters (for example a store whose value is JSON-serialized or compared by reference). Exemplar: createPersistedState in packages/svelte-utils.
- Prefer
$derived for computed state. Treat $effect as a browser-only escape hatch for DOM integration, analytics, subscriptions, and external systems. A returned cleanup runs before the effect re-runs and when the component is destroyed.
- Props can change. Values derived from
$props() should usually be $derived, not one-time initialization.
- Treat props as parent-owned by default. Use callback props for commands and
$bindable only for intentional two-way APIs such as UI wrappers, bind:value, bind:open, and bind:ref.
- Prefer snippets and
{@render} over slots for new Svelte 5 code. Type exposed snippet props with Snippet from svelte; use tuple parameters such as Snippet<[Row]>.
- Avoid legacy patterns in runes-mode code:
$: declarations, export let, on:click, <slot>, <svelte:component>, <svelte:self>, beforeUpdate, afterUpdate, and createEventDispatcher.
- Use event attributes and callback props:
onclick={...}, onkeydown={...}, and onSelect={() => ...} style props. Do not add on: directives or dispatch component events in new runes-mode code.
Core Decisions
- If a disposable resource identity depends on a prop, let the parent own mount and unmount with
{#key} or {#if}; open the resource synchronously in the child. Read lifecycle and reactivity.
- If readiness is a stable promise, use
{#await} in the template instead of a $state(false) flag and a cancellation effect.
- Inline shallow property aliases and single-use script helpers (a
function, $derived, or one-off const used once in the template). Keep one extracted only when it computes, narrows, or stabilizes something useful, or when a justifying comment plus a semantic name makes the template read better. Read component and UI patterns.
- Map finite unions with a
satisfies Record lookup, not nested ternaries or $derived.by() switches.
- Use
SvelteMap for ID-keyed collections where get, has, size, or iteration should update reactively. Values inside a SvelteMap are not deep-proxied, so store reactive row objects or replace values when nested data changes. Convert maps to stable arrays with $derived before passing them to table-like consumers.
- Use
SvelteSet for an id set whose membership (has, size, iteration) is read in a reactive or template context: add/delete then drive the UI directly, replacing $state<string[]> plus spread/filter reassignment. Reach for SvelteMap instead the moment the set needs to carry per-key data (a timestamp, a last error). Use a plain Set/Map (not the reactive class) when the collection is read only in imperative code, such as a subscription's listener bag: a reactive wrapper read outside any effect is cost with no reader (exemplar: the plain listeners set in createPersistedState).
- Bridge an external event source (a Y.Doc
update, chrome.storage, window events, an auth store) into reactivity with createSubscriber from svelte/reactivity, not a hand-rolled $state plus $effect plus listener set: reads inside an effect become reactive and the subscription is ref-counted to effect usage (start on first subscriber, cleanup at zero). Exemplars: , , in . Keep a manual listener set only when the same source also serves imperative / consumers whose liveness cannot ride on effect ref-counting (again ).
Reference Map
- Read Lifecycle and reactivity when a change touches keyed resources, readiness promises,
$effect cleanup, shallow aliases, value maps, SvelteMap, table state, or .svelte.ts state modules.
- Read Mutations and workspace inputs when a change touches TanStack Query mutation placement, inline handlers, async button states, direct
await, or workspace-backed text inputs.
- Read Component and UI patterns when a change touches shadcn-svelte imports,
$props typing, $bindable, snippets, DOM attachments, self-contained dialogs, view branching, repetitive markup, single-use helper inlining, loading or empty states, prop-first derivation, or template text gotchas.