mcpField
S
svelte5

svelte5

github.com/joshuadavidthomasDevelopment6044 installsUpdated 14w ago
Repository

About svelte5

svelte5 is a skill for developers writing and reviewing Svelte 5 components. It centers state ownership, explicit data flow, and semantic markup, while helping identify legacy syntax and common anti-patterns.

Key features

  1. 01Svelte 5 reactivity principles
  2. 02Component state and prop modeling
  3. 03Component API and HTML semantics review
  4. 04Code smell checks and rewrite guidance
  5. 05Distinguishing Svelte 4 and Svelte 5 projects

Use cases

  1. 01Reviewing data flow in Svelte 5 components
  2. 02Replacing effects with derived state or event handlers
  3. 03Checking accessibility and SSR state risks

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/joshuadavidthomas/agent-skills --skill svelte5

After installing, type/svelte5in Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

README.md
references/
actions-vs-components.md
actions.md
attachments.md
bindable-by-default.md
bindings-and-directives.md
class-state-common-mistakes.md
class-state-patterns.md
class-state-ssr-safety.md
component-patterns.md
context-identity.md
context-vs-scoped-state.md
debugging.md
deep-state-without-immutable-ceremony.md
effect-driven-state.md
imperative-api.md
prop-mirroring.md
read-tracked-reactivity.md
runes-common-mistakes.md
runes-component-api.md
runes-reactivity-patterns.md
semantic-html-first.md
shadcn-svelte-forms.md
snippets-as-render-functions.md
snippets-vs-slots.md
special-elements.md
ssr-state-leaks.md
state-ownership.md
static-runes.md
stores.md

Details

From the project README

Think in Svelte 5

You already know Svelte syntax. This skill changes your defaults — what you reach for first when designing a component, placing state, modeling reactivity, and reviewing UI code.

The core failure mode is Svelte that compiles but thinks like React, Vue, or Svelte 4 — effects standing in for derived values and events, props mirrored into state, global stores by reflex, two-way binding as the default, clickable divs, Svelte 4 component APIs in new code.

The component is a small reactive program with visible dependencies. Keep dataflow direct, state ownership obvious, and markup semantic; let the compiler and the DOM do the work.

This skill is the general-purpose entry point for Svelte component review; for SvelteKit-level concerns, also use sveltekit (see Cross-References).

Treat these as strong defaults, not rigid laws: when unsure, choose the approach that makes ownership, dependencies, and user semantics more explicit.

How Svelte Thinks

Make reactivity visible

1. Reactivity is read-tracked. A $derived/$effect depends on what it reads while running; if one reruns unexpectedly, inspect its reads, not a dependency array. See references/read-tracked-reactivity.md.

2. Derived state is $derived, not $effect. Pure functions of other state get derived; effects are for side effects, not keeping variables in sync. See references/effect-driven-state.md.

<!-- ❌ effect writing derived state -->
let doubled = $state(0);
$effect(() => { doubled = count * 2; });

<!-- ✅ derive it -->
let doubled = $derived(count * 2);

3. Effects are escape hatches. Before $effect, check for a derived value, an event handler, or a bind: getter/setter. Use it only to touch the outside world — subscriptions, timers, observers, imperative APIs, logging — and return cleanup.

4. Runes are statically analyzable. Compiler syntax, not runtime hooks — reusable state becomes .svelte.ts classes and factories, not custom hooks. See references/static-runes.md.

5. $state is a deep proxy, not React state. Mutate what changed in local arrays and objects; skip the immutable-update ceremony. See references/deep-state-without-immutable-ceremony.md.

Put state where ownership is clearest

6. State has an owner. Local interaction state → component; reusable behavior → .svelte.ts class; descendant-shared → context; stores only for the store contract, not every changing value. See references/state-ownership.md.

7. Do not mirror props unless you mean "draft." Copying props into $state creates two sources of truth — derive from props, or make a named editable draft with reset/commit. See references/prop-mirroring.md.

<!-- ❌ prop mirrored into local state -->
let { value } = $props();
let local = $state(value); // stale if parent changes

<!-- ✅ derive from prop -->
let { value } = $props();
let display = $derived(value.toUpperCase());

8. Context shares identity, not provider rerenders. Put a reactive object/class in context and mutate its properties; replacing plain values won't behave like React Provider updates. See references/context-identity.md.

9. Module-level mutable state is suspicious in SSR apps. In SvelteKit, exported mutable instances leak between requests — use factories, context, or request-owned data. See references/ssr-state-leaks.md.

Design component APIs around ownership

10. Props describe inputs; callbacks describe events. Component events are callback props; avoid createEventDispatcher in new code unless preserving an old public API. See references/component-patterns.md.

<!-- ❌ createEventDispatcher in Svelte 5 -->
const dispatch = createEventDispatcher();
function handleClick() { dispatch('select', item); }

<!-- ✅ callback prop -->
let { onSelect } = $props();
function handleClick() { onSelect?.(item); }

11. Two-way binding is an API commitment. $bindable means the child may mutate parent-owned state — use it for form controls and deliberate controlled components, not as a default. See references/bindable-by-default.md.

12. Snippets are render functions, not renamed slots. Use them when the parent supplies UI; type their parameters and name them by role. See references/snippets-as-render-functions.md.

13. Wrapper components should preserve the platform. Wrapping a button means accepting button attributes and keeping type, disabled, focus, and ARIA intact. See references/wrapper-components-preserve-html.md.

Let HTML and the compiler work

14. Native elements before custom behavior. A button already handles keyboard, focus, disabled, and a11y; a clickable div rebuilds the platform badly. See references/semantic-html-first.md.

15. Design-system fields should preserve form semantics. In shadcn-svelte or bits-ui forms, use Field.* for labels, groups, descriptions, and errors — not raw divs, separate Label imports, or clickable option rows. See references/shadcn-svelte-forms.md.

16. Components own markup; actions/attachments own DOM behavior. Renders UI → component. Attaches reusable imperative behavior to an element → action or attachment. See references/actions-vs-components.md.

17. Svelte 5 syntax should be consistent. New code uses $props, onclick-style attributes, snippets, and callback props; don't mix old syntax outside legacy maintenance. See references/svelte5-syntax-discipline.md.

18. Type the boundary, not every breath. Non-trivial components get a Props type; type snippets and callbacks; use svelte/elements for wrappers; avoid broad any at boundaries. See references/typescript.md.

Running a Review

  1. Detect the version first. Read package.json for the svelte major and check svelte.config.*. In a Svelte 5 project, flag Svelte 4 patterns (export let, on:event, <slot>, createEventDispatcher); in a Svelte 4 project, do not recommend Svelte 5-only syntax unless the task is migration.
  2. Apply the principles above; scan the smell index below. Open the linked reference before proposing a rewrite.
  3. Judge performance only on evidence or obvious scale. Key identified {#each}, move heavy work out of markup into $derived, avoid needless two-way bindings. Most code needs no manual optimization.
  4. Shape the output: high-impact first (correctness, reactivity, a11y, SSR leaks), then suggested rewrites (smallest useful change), then nice-to-haves. Tie every point to behavior, maintainability, or user impact — not every stylistic nit.

Code Smell Index

Scan for the smell; the principle above carries the fix.

Code smellReference
Old Svelte syntax in new codesvelte5-syntax-discipline
Effect assigns a derived valueeffect-driven-state
Effect responds to a control changingeffect-driven-state
Effect converts a bound valuebindings-and-directives
Effect reruns mysteriouslyread-tracked-reactivity
Rune called inside a helper or hookstatic-runes
Immutable-update ceremony on local statedeep-state-without-immutable-ceremony
Prop copied into local stateprop-mirroring
Global store by default / owner unclearstate-ownership
Context value replaced instead of mutatedcontext-identity
Exported mutable singleton in SvelteKitssr-state-leaks
createEventDispatcher to emit an eventcomponent-patterns
$bindable by habitbindable-by-default
Slot-shaped API (export let, <slot>)snippets-as-render-functions
Clickable div / spansemantic-html-first
shadcn-svelte form rebuilt with raw wrappersshadcn-svelte-forms
Wrapper that hides native behaviorwrapper-components-preserve-html
Action that owns markup/stateactions-vs-components
Dynamic list left unkeyedbindings-and-directives
Broad any at the component boundarytypescript
{@html} with user contenttemplate-tags
Component behavior left untestedtesting

Cross-References

  • sveltekit — Routes, layouts, load, form actions, remote functions, cookies, auth, endpoints, redirects, server errors, app-level SSR/data flow

Comments

Markdown supported