Help us improve
Share bugs, ideas, or general feedback.
From frontend
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.
npx claudepluginhub xobotyi/cc-foundry --plugin frontendHow this skill is triggered — by the user, by Claude, or both
Slash command
/frontend:svelteThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Reactivity is explicit, compiler-driven, and minimal-runtime.** Every reactive declaration uses a `$` rune. The
Enforces Svelte 5 best practices in SvelteKit: runes ($state, $derived, $effect), $props(), $bindable(), load functions, form actions, and SSR patterns to fix outdated Svelte 4 code.
Provides best practices for Svelte runes: $state for reactive variables, $derived for computations, minimal $effect use, reactive $props handling, and $inspect.trace debugging. For Svelte component writing, editing, analysis.
Builds full-stack SvelteKit web apps with file-based routing, SSR, SSG, API routes, form actions, and load functions. Activates for +page.svelte, +layout.svelte, or Svelte full-stack queries.
Share bugs, ideas, or general feedback.
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.
${CLAUDE_SKILL_DIR}/references/runes.md]: $state, $derived, $effect, $props, $bindable
details${CLAUDE_SKILL_DIR}/references/components.md]: Snippets, events, context, special elements${CLAUDE_SKILL_DIR}/references/sveltekit.md]: Routing, load functions, form actions, hooks, imports$state$state or $state.raw. Plain let declarations are not reactive.$state objects breaks reactivity -- destructured values are snapshots, not live references.$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).Set, Map, Date, URL from svelte/reactivity when you need reactive built-in types.Cannot directly export reassignable $state. Two patterns:
$state({ count: 0 }) as a const, mutate properties, export modifier
functions.$state private, export getCount() and increment().Runes only work in .svelte and .svelte.js/.svelte.ts files.
$derived$derived for all computed values -- never synchronize state with $effect.$derived.by(() => { ... }) for complex derivations needing a function body.untrack to exempt specific reads.$derived values are individually reactive.$effect$effect is an escape hatch. Use only for side effects: DOM manipulation, analytics, third-party library calls,
timers.await or inside setTimeout are NOT tracked.$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.
$propslet { name, count = 0 } = $props().let { name }: Props = $props().let { class: klass } = $props().let { a, b, ...rest } = $props().let props = $props().$props.id() -- consistent across SSR/hydration.$bindable. Use callback props to
communicate changes upward.$bindablelet { value = $bindable() } = $props().bind:value={variable}.$inspect$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.$hostOnly available inside custom elements. Provides access to the host element for dispatching custom events.
$props())$state)$derived)$effect, sparingly)<style>)<MyComponent />. Required for dynamic rendering.item.component).<svelte:component> is unnecessary. Just use <Thing /> where Thing is a
reactive variable.onclick={handler}, never on:click={handler}.onclick listens to click, onClick listens to Click.event.preventDefault() / event.stopPropagation() in the handler. For capture, append to
event name: onclickcapture={...}.let { onEvent } = $props(). Never use
createEventDispatcher.click, input, keydown) -- single listener at app root. When
manually dispatching events, set { bubbles: true }. Prefer on from svelte/events over raw addEventListener.{@render children?.()} for default content. Never use <slot />.{#snippet header()}...{/snippet} in parent, accept as props, render with
{@render header()}.{@render item(entry)} in child, {#snippet item(text)} in
parent.{@render children?.()} or {#if children} with fallback.<script module> for cross-component use.Snippet and Snippet<[ParamType]> from svelte.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 }}.
setContext(key, value) / getContext(key) passes data through the component tree without prop drilling.createContext<T>() from svelte which returns [getContext, setContext] pair.setContext to maintain reactivity across boundaries.<svelte:boundary> -- error boundary. Use {#snippet failed(error, reset)} for error UI and {#snippet pending()}
for loading state with await expressions.<svelte:window> -- bind to window events and properties (bind:scrollY).<svelte:head> -- insert elements into document.head (SEO meta tags, title).<svelte:element this={tag}> -- render a dynamic HTML element.<svelte:options> -- set compiler options (customElement, namespace).Components are functions, not classes:
mount(Component, { target }) for client-side mounting.unmount(app) to destroy.hydrate instead of mount for server-rendered HTML.$state is shared across requests during SSR. Use context or
event.locals instead.load, don't write to globals. No side effects in load functions.setContext/getContext for data that must not leak between requests.$derived for reactive computed values in components -- plain assignments in <script> run once, not reactively..svelte.js / .svelte.ts for reactive modules -- runes only work in .svelte and .svelte.js/.svelte.ts files.$lib for shared code -- import from $lib/ instead of relative paths climbing multiple levels.+page.svelte — Page component (receives data from load)+page.js — Universal load (server + browser)+page.server.js — Server-only load + form actions+layout.svelte — Layout wrapper (must render {@render children()})+layout.js — Layout universal load+layout.server.js — Layout server load+error.svelte — Error boundary+server.js — API endpoint (GET, POST, etc.)Key rules: all files can run on the server. All run on the client except +server files. +layout and +error apply
to subdirectories too.
Decision tree:
| Need | Use |
|---|---|
| Database, private keys | +page.server.js (PageServerLoad) |
| Non-serializable return values | +page.js (PageLoad) |
| External API, no secrets | +page.js (PageLoad) |
| Both | Both (server data flows to universal) |
Universal vs server:
| Aspect | Universal (+page.js) | Server (+page.server.js) |
|---|---|---|
| Runs on | Server (SSR) + Browser | Server only |
| Access | params, url, fetch | + cookies, locals, request |
| Returns | Any value (classes, components) | Serializable data only |
fetch, not global fetch -- inherits cookies, makes relative requests work on server, bypasses
HTTP overhead for internal requests.+page.js: prerender, ssr, csr.params change, url properties change, parent() was
called and parent reran, or invalidate()/invalidateAll() called.error() and redirect() from @sveltejs/kit for error and redirect responses.Server-only POST handlers in +page.server.js. Work without JavaScript.
export const actions = { default: async ({ request }) => { ... } }.action="?/login" on form, multiple actions in the actions object.fail(400, { field, missing: true }) from action. Access via form prop in the page component.use:enhance from $app/forms for JS-enhanced submission without full page reload.Export HTTP verb handlers from +server.js: GET, POST, PUT, PATCH, DELETE. Return json() or
new Response().
Server hooks (src/hooks.server.js):
handle({ event, resolve }) -- intercept every request. Set event.locals, modify response headers.handleFetch -- modify server-side fetch calls.handleError -- log and sanitize unexpected errors.init -- run once at server startup.Client hooks (src/hooks.client.js):
handleError -- client-side error handling.Universal hooks (src/hooks.js):
reroute -- rewrite URLs before routing.transport -- serialize/deserialize custom types across server/client boundary.Most-used modules: $app/navigation (goto, invalidate), $app/state (page, navigating), $app/forms
(enhance), $env/static/private and $env/static/public for environment variables, $lib for shared code. Full
imports table in ${CLAUDE_SKILL_DIR}/references/sveltekit.md.
load functions to avoid browser-to-API waterfalls.$derived instead of $effect for computed values.<body>).@sveltejs/enhanced-img for image optimization.import() for conditional code.When writing Svelte code:
When reviewing Svelte code:
This skill provides Svelte-specific conventions. The coding skill governs workflow; for TypeScript projects, the typescript skill handles language-level choices; for CSS concerns, the css skill handles styling conventions.