# Svelte

> Svelte 5 - Reactive UI framework with compiler magic, Runes API, SvelteKit full-stack framework, SSR/SSG, minimal JavaScript

- **Type:** Skill
- **Install:** `agentstack add skill-bobmatnyc-claude-mpm-skills-svelte`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [bobmatnyc](https://agentstack.voostack.com/s/bobmatnyc)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [bobmatnyc](https://github.com/bobmatnyc)
- **Source:** https://github.com/bobmatnyc/claude-mpm-skills/tree/main/toolchains/javascript/frameworks/svelte

## Install

```sh
agentstack add skill-bobmatnyc-claude-mpm-skills-svelte
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Svelte 5 - Compiler-First Reactive Framework

## Overview

Svelte is a **compiler-based** reactive UI framework that shifts work from runtime to build time. Unlike React/Vue, Svelte compiles components to highly optimized vanilla JavaScript with minimal overhead. **Svelte 5** introduces Runes API for explicit, fine-grained reactivity.

**Key Features**:
- **Runes API**: $state, $derived, $effect for explicit reactivity
- **Zero runtime overhead**: Compiles to vanilla JS
- **Built-in state management**: No external libraries needed
- **SvelteKit**: Full-stack framework with SSR/SSG/SPA
- **Write less code**: Simple, readable component syntax
- **Exceptional performance**: Small bundles, fast runtime

**Installation**:
```bash
# Create new SvelteKit project
npm create svelte@latest my-app
cd my-app
npm install
npm run dev

# Or Svelte only (no SvelteKit)
npm create vite@latest my-app -- --template svelte-ts
```

## Svelte 5 Runes API (Modern Approach)

### State Management with $state

```svelte

  // Reactive state - automatically tracks changes
  let count = $state(0);
  let user = $state({ name: 'Alice', age: 30 });

  // Arrays and objects are deeply reactive
  let todos = $state([]);

  function addTodo(text: string) {
    todos.push({ id: Date.now(), text, done: false });
    // No need for todos = [...todos] like React!
  }

  function increment() {
    count++; // Triggers reactivity
  }

  Clicked {count} times

```

### Computed Values with $derived

```svelte

  let firstName = $state('John');
  let lastName = $state('Doe');

  // Automatically updates when dependencies change
  let fullName = $derived(`${firstName} ${lastName}`);
  let greeting = $derived(`Hello, ${fullName}`);

  // Complex derivations
  let items = $state([1, 2, 3, 4, 5]);
  let total = $derived(items.reduce((sum, n) => sum + n, 0));
  let average = $derived(total / items.length);

{greeting}
Average: {average.toFixed(2)}
```

### Side Effects with $effect

```svelte

  let count = $state(0);
  let logs = $state([]);

  // Runs when dependencies change
  $effect(() => {
    console.log(`Count is now: ${count}`);
    logs.push(`Count changed to ${count}`);

    // Optional cleanup function
    return () => {
      console.log('Cleaning up previous effect');
    };
  });

  // Effect with external subscriptions
  $effect(() => {
    const interval = setInterval(() => {
      count++;
    }, 1000);

    return () => clearInterval(interval);
  });

```

### Component Props with $props

```svelte

  interface Props {
    title: string;
    count?: number;
    onUpdate?: (value: number) => void;
  }

  // Type-safe props with defaults
  let { title, count = 0, onUpdate } = $props();

  // Props are read-only, but can derive from them
  let displayTitle = $derived(title.toUpperCase());

{displayTitle}
Count: {count}
 onUpdate?.(count + 1)}>
  Increment

```

### Two-Way Binding with $bindable

```svelte

  interface Props {
    value: string;
    placeholder?: string;
  }

  // Allows parent to bind to this prop
  let { value = $bindable(''), placeholder = 'Search...' } = $props();

  import SearchInput from './SearchInput.svelte';

  let query = $state('');
  let results = $derived(query ? search(query) : []);

Found {results.length} results for "{query}"
```

## Component Patterns

### Basic Component Structure

```svelte

  let count = $state(0);
  let doubled = $derived(count * 2);

  function increment() {
    count++;
  }

  function decrement() {
    count--;
  }

  -
  Count: {count} (Doubled: {doubled})
  +

  .counter {
    display: flex;
    gap: 1rem;
    align-items: center;
  }

  button {
    padding: 0.5rem 1rem;
    font-size: 1.2rem;
  }

```

### Conditional Rendering

```svelte

  let loggedIn = $state(false);
  let user = $state(null);
  let loading = $state(true);

{#if loading}
  Loading...
{:else if loggedIn && user}
  Welcome, {user.name}!
{:else}
  Please log in
{/if}
```

### Lists and Keyed Each Blocks

```svelte

  interface Todo {
    id: number;
    text: string;
    done: boolean;
  }

  let todos = $state([
    { id: 1, text: 'Learn Svelte', done: true },
    { id: 2, text: 'Build app', done: false }
  ]);

  function toggle(id: number) {
    const todo = todos.find(t => t.id === id);
    if (todo) todo.done = !todo.done;
  }

  {#each todos as todo (todo.id)}
    
       toggle(todo.id)}
      />
      {todo.text}
    
  {/each}

  .done {
    text-decoration: line-through;
    opacity: 0.6;
  }

```

## SvelteKit Framework

### Project Structure

```
my-app/
├── src/
│   ├── routes/
│   │   ├── +page.svelte          # Home page
│   │   ├── +page.ts              # Universal load
│   │   ├── +page.server.ts       # Server load
│   │   ├── +layout.svelte        # Shared layout
│   │   ├── about/
│   │   │   └── +page.svelte      # /about
│   │   └── blog/
│   │       ├── +page.svelte      # /blog
│   │       └── [slug]/
│   │           └── +page.svelte  # /blog/my-post
│   ├── lib/
│   │   ├── components/
│   │   ├── stores/
│   │   └── utils/
│   └── app.html
├── static/                        # Static assets
└── svelte.config.js
```

### Load Functions (Data Fetching)

```typescript
// src/routes/blog/[slug]/+page.ts
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params, fetch }) => {
  const response = await fetch(`/api/posts/${params.slug}`);
  const post = await response.json();

  return {
    post
  };
};
```

```svelte

  import type { PageData } from './$types';

  let { data } = $props();

  {data.post.title}
  {@html data.post.content}

```

### Server-Only Load Functions

```typescript
// src/routes/admin/+page.server.ts
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ locals }) => {
  if (!locals.user?.isAdmin) {
    throw redirect(303, '/login');
  }

  const users = await db.users.findMany();

  return {
    users
  };
};
```

### Form Actions

```typescript
// src/routes/login/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});

export const actions = {
  default: async ({ request, cookies }) => {
    const formData = await request.formData();
    const data = Object.fromEntries(formData);

    const result = schema.safeParse(data);
    if (!result.success) {
      return fail(400, {
        errors: result.error.flatten().fieldErrors
      });
    }

    const user = await authenticateUser(result.data);
    if (!user) {
      return fail(401, { message: 'Invalid credentials' });
    }

    cookies.set('session', user.sessionToken, { path: '/' });
    throw redirect(303, '/dashboard');
  }
} satisfies Actions;
```

```svelte

  import type { ActionData } from './$types';

  let { form } = $props();

  
  {#if form?.errors?.email}
    {form.errors.email[0]}
  {/if}

  
  {#if form?.errors?.password}
    {form.errors.password[0]}
  {/if}

  {#if form?.message}
    {form.message}
  {/if}

  Log In

```

## State Management Patterns

### Runes-Based Store (Modern)

```typescript
// src/lib/stores/cart.svelte.ts
interface CartItem {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

function createCart() {
  let items = $state([]);

  let total = $derived(
    items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  );

  let itemCount = $derived(
    items.reduce((sum, item) => sum + item.quantity, 0)
  );

  return {
    get items() { return items; },
    get total() { return total; },
    get itemCount() { return itemCount; },

    addItem(item: Omit) {
      const existing = items.find(i => i.id === item.id);
      if (existing) {
        existing.quantity++;
      } else {
        items.push({ ...item, quantity: 1 });
      }
    },

    removeItem(id: number) {
      items = items.filter(i => i.id !== id);
    },

    clear() {
      items = [];
    }
  };
}

export const cart = createCart();
```

```svelte

  import { cart } from '$lib/stores/cart.svelte';

  Items: {cart.itemCount}
  Total: ${cart.total.toFixed(2)}

   cart.addItem({ id: 1, name: 'Widget', price: 9.99 })}>
    Add Widget
  

```

### Legacy Svelte Store (Svelte 4 Style)

```typescript
// src/lib/stores/user.ts
import { writable, derived } from 'svelte/store';

interface User {
  id: number;
  name: string;
  email: string;
}

function createUserStore() {
  const { subscribe, set, update } = writable(null);

  return {
    subscribe,
    login: (user: User) => set(user),
    logout: () => set(null),
    updateName: (name: string) => update(u => u ? { ...u, name } : null)
  };
}

export const user = createUserStore();

// Derived store
export const isLoggedIn = derived(user, $user => $user !== null);
```

```svelte

  import { user, isLoggedIn } from '$lib/stores/user';

{#if $isLoggedIn}
  Welcome, {$user?.name}!
{:else}
  Please log in
{/if}
```

## Animations and Transitions

### Built-in Transitions

```svelte

  import { fade, slide, fly, scale } from 'svelte/transition';
  import { quintOut } from 'svelte/easing';

  let visible = $state(true);

 visible = !visible}>
  Toggle

{#if visible}
  
    Fades in and out
  

  
    Slides in and out
  

  
    Flies in from bottom
  
{/if}
```

### Custom Transitions

```typescript
// src/lib/transitions.ts
export function blur(node: HTMLElement, { duration = 300 }) {
  return {
    duration,
    css: (t: number) => `
      opacity: ${t};
      filter: blur(${(1 - t) * 10}px);
    `
  };
}
```

```svelte

  import { blur } from '$lib/transitions';
  let show = $state(true);

{#if show}
  
    Custom blur transition
  
{/if}
```

### Animate Directive (FLIP Animations)

```svelte

  import { flip } from 'svelte/animate';
  import { quintOut } from 'svelte/easing';

  let items = $state([1, 2, 3, 4, 5]);

  function shuffle() {
    items = items.sort(() => Math.random() - 0.5);
  }

Shuffle

  {#each items as item (item)}
    
      {item}
    
  {/each}

```

## Advanced Features

### Actions (Element Behaviors)

```typescript
// src/lib/actions.ts
export function clickOutside(node: HTMLElement, callback: () => void) {
  const handleClick = (event: MouseEvent) => {
    if (!node.contains(event.target as Node)) {
      callback();
    }
  };

  document.addEventListener('click', handleClick, true);

  return {
    destroy() {
      document.removeEventListener('click', handleClick, true);
    }
  };
}
```

```svelte

  import { clickOutside } from '$lib/actions';

  let showMenu = $state(false);

 showMenu = !showMenu}>
  Menu

{#if showMenu}
   showMenu = false}
  >
    
      Item 1
      Item 2
    
  
{/if}
```

### Slots and Component Composition

```svelte

  let { title } = $props();

  
    {#if title}
      {title}
    {:else}
      Default Header
    {/if}
  

  
    Default content
  

  
    
  

  This is the main content

  
    Action
  

```

### Special Elements

```svelte

  let Component = $state(A);
  let tag = $state('div');

  Content

 console.log('Window resized')}
  onkeydown={(e) => console.log(e.key)}
/>

  My Page
  

```

## Migration from React/Vue

### React to Svelte 5

| React | Svelte 5 | Notes |
|-------|----------|-------|
| `useState(0)` | `$state(0)` | Direct state |
| `useMemo(() => x * 2, [x])` | `$derived(x * 2)` | Auto-tracked |
| `useEffect(() => {...}, [x])` | `$effect(() => {...})` | Auto deps |
| `props.name` | `let { name } = $props()` | Destructure |
| `{show && }` | `{#if show}{/if}` | Explicit |

### Vue 3 to Svelte 5

| Vue 3 | Svelte 5 | Notes |
|-------|----------|-------|
| `ref(0)` | `$state(0)` | Direct state |
| `computed(() => x * 2)` | `$derived(x * 2)` | Similar |
| `watch(() => x, ...)` | `$effect(() => {...})` | Auto-tracked |
| `defineProps()` | `let { name } = $props()` | Type-safe |
| `v-if="show"` | `{#if show}` | Block syntax |

## Performance Best Practices

1. **Use $derived over $effect** when only computed values are needed
2. **Avoid unnecessary $effect** - only for side effects, not computations
3. **Leverage compiler optimizations** - Svelte does most work at build time
4. **Use keyed each blocks** - `{#each items as item (item.id)}`
5. **Lazy load components** - `const Component = await import('./Heavy.svelte')`
6. **SSR for initial load** - Use SvelteKit's SSR capabilities
7. **Optimize bundles** - Use adapters for deployment targets

## Testing

### Unit Tests with Vitest

```typescript
// Counter.test.ts
import { render, fireEvent } from '@testing-library/svelte';
import { expect, test } from 'vitest';
import Counter from './Counter.svelte';

test('increments counter on click', async () => {
  const { getByText } = render(Counter);

  const button = getByText('+');
  await fireEvent.click(button);

  expect(getByText(/Count: 1/)).toBeInTheDocument();
});
```

### E2E with Playwright

```typescript
// tests/login.test.ts
import { expect, test } from '@playwright/test';

test('user can log in', async ({ page }) => {
  await page.goto('/login');

  await page.fill('input[name="email"]', 'user@example.com');
  await page.fill('input[name="password"]', 'password123');
  await page.click('button[type="submit"]');

  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('text=Welcome')).toBeVisible();
});
```

## Deployment

### Adapters

```javascript
// svelte.config.js
import adapter from '@sveltejs/adapter-vercel'; // or adapter-node, adapter-static

export default {
  kit: {
    adapter: adapter()
  }
};
```

**Available Adapters**:
- `adapter-auto`: Auto-detect platform
- `adapter-vercel`: Vercel deployment
- `adapter-node`: Node.js server
- `adapter-static`: Static site generation
- `adapter-cloudflare`: Cloudflare Pages/Workers
- `adapter-netlify`: Netlify deployment

## Resources

- **Svelte Docs**: https://svelte.dev/docs
- **SvelteKit Docs**: https://kit.svelte.dev/docs
- **Svelte 5 Runes**: https://svelte-5-preview.vercel.app/docs/runes
- **Tutorial**: https://learn.svelte.dev
- **REPL**: https://svelte.dev/repl

## Summary

- **Svelte 5** uses Runes API ($state, $derived, $effect) for explicit reactivity
- **Compiler-first** - shifts work to build time for minimal runtime overhead
- **SvelteKit** provides full-stack capabilities with SSR/SSG/SPA modes
- **Write less code** - simpler syntax than React/Vue
- **Exceptional performance** - small bundles, fast runtime
- **Migration-friendly** - Svelte 4 and 5 can coexist
- **Type-safe** - First-class TypeScript support

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [bobmatnyc](https://github.com/bobmatnyc)
- **Source:** [bobmatnyc/claude-mpm-skills](https://github.com/bobmatnyc/claude-mpm-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-bobmatnyc-claude-mpm-skills-svelte
- Seller: https://agentstack.voostack.com/s/bobmatnyc
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
