agentsclimarketplace

Svelte expert

Skill Akayashuu/agent-skills/skills/svelte-expert

Framework & language expert skills for Claude Code — idiomatic best practices for TypeScript, React, Vue, Svelte, Solid, Angular, Astro

Install
npx -y skills add Akayashuu/agent-skills --skill svelte-expert

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing, reviewing, or refactoring Svelte 5 components with runes — reaching for $state, $derived, $effect, $props, $bindable, snippets, stores, or shared reactive state in SvelteKit, or migrating legacy $:/export let code.

SKILL.md

5.9 KB, as published. Nobody here has run it

Svelte Expert

Overview

Svelte 5 replaces compiler-magic reactivity with explicit runes. The mental model is closer to fine-grained signals than to Svelte 4. Most "outdated" code uses $:, export let, and writable stores for local state — all now legacy. Reach for $effect rarely: it is for side effects, not for computing values (same smell as misused React effects).

Quick Reference

GoalDoAvoid
Reactive local statelet x = $state(0)top-level let (no longer reactive)
Computed value$derived(a + b) / $derived.by(() => …)$: reactive statements
Component inputslet { x } = $props() + TS typeexport let x
Two-way bindinglet { v = $bindable() } = $props()manual event dispatch round-trips
Side effect / sync external$effect(() => …)using it to derive state
Effect cleanupreturn () => teardown()leaking listeners/timers
Shared reactive staterune state in .svelte.ts modulewritable store for everything
Cross-cutting / RxJS interopwritable/readable storereinventing with runes
List rendering{#each items as it (it.id)}unkeyed {#each}
Reusable markup{#snippet} / {@render}slots (legacy)

Core Patterns

State + derived — never compute with $effect:

<script lang="ts">
  // ❌ legacy + effect-as-derivation: extra render, stale risk
  // export let items: Item[];
  // $: total = items.reduce((n, i) => n + i.price, 0);
  // let count = 0;
  // $effect(() => { count = items.length; }); // wrong: derive, don't sync

  // ✅ runes
  let { items }: { items: Item[] } = $props();
  const total = $derived(items.reduce((n, i) => n + i.price, 0));
  const count = $derived(items.length);
</script>

Runnable (state factory + $derived / $derived.by): examples/state-derived.svelte.ts

$props with types and $bindable — replaces export let:

<script lang="ts">
  let {
    value = $bindable(''),     // two-way: <Input bind:value/>
    placeholder = 'Search',    // plain prop with default
    onsubmit,                  // callback prop, not createEventDispatcher
  }: { value?: string; placeholder?: string; onsubmit?: (v: string) => void } = $props();
</script>

$effect only for external systems, with cleanup:

<script lang="ts">
  let { roomId }: { roomId: string } = $props();
  let messages = $state<Msg[]>([]);

  $effect(() => {
    const sock = connect(roomId);          // re-runs when roomId changes
    sock.on('msg', (m) => messages.push(m)); // deep proxy: mutate, don't reassign
    return () => sock.close();             // cleanup before re-run / unmount
  });
</script>

Use $effect.pre(() => …) (same API, runs before DOM updates) for the rare case of reading layout before a render — e.g. capturing scroll position for autoscroll.

Runnable ($effect cleanup + $effect.pre): examples/effect-cleanup.svelte.ts

Shared state — .svelte.ts module, not a store:

// counter.svelte.ts
let count = $state(0);              // private: can't export a reassigned $state directly
export const counter = {
  get value() { return count; },   // getter exposes the live reactive read
  inc() { count++; },
};
// any component: import { counter } — reactive across the app

The compiler wraps reactivity per file, so a directly exported primitive $state won't stay reactive when reassigned elsewhere. Export an object (mutate its fields) or a getter/function API. See shared.svelte.ts for both patterns.

Fine-grained reactivity: $state returns a deep proxy. Mutate in place (obj.field = x, arr.push(...)) — reassigning the whole object is unnecessary and loses fine-grained tracking. Use (item.id) keys in {#each} so Svelte moves DOM nodes instead of recreating and remounting them.

Common Mistakes

  • $: / export let in new code — Svelte 4 idioms; use $derived / $props.
  • $effect to derive state — causes extra passes and stale values; use $derived/$derived.by.
  • Effect-driven loops — an $effect that reads and writes the same $state loops infinitely. Prefer $derived; only if you must write state in an effect, read the looping dependency via untrack(() => …). Runnable: examples/derived-not-effect.svelte.ts.
  • Writable store for component-local state — use $state; reserve stores for cross-cutting concerns or external (RxJS) interop.
  • Reassigning whole objects — breaks fine-grained updates; mutate proxy fields directly.
  • Unkeyed {#each} — wrong DOM reuse on reorder; always provide (item.id).
  • createEventDispatcher / slots — replaced by callback props and snippets.

When NOT to over-engineer

A small leaf component with one prop and no derived state needs no ceremony — let { label } = $props() is the whole story. Don't build a .svelte.ts store for state one component owns. Don't wrap $derived around a value used once inline. Runes are cheap; reach for shared modules and $effect only when something actually crosses component boundaries or touches the outside world.

Sources

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.