svelte-development
Svelte 5 development with runes ($state, $derived, $effect), SvelteKit full-stack framework, and modern reactive patterns. Use when building Svelte applications, implementing fine-grained reactivity, or working with SvelteKit routing and server functions.
What this skill does
# Svelte 5 Development
Comprehensive guide for building modern Svelte applications with runes and SvelteKit.
## Stack Overview
| Tool | Purpose | Version |
| ---------- | -------------------- | ------- |
| Svelte 5 | Core framework | 5.0+ |
| SvelteKit | Full-stack framework | 2.0+ |
| TypeScript | Type safety | 5.0+ |
| Vite | Build tool | 5.0+ |
| Vitest | Testing | 1.0+ |
---
## Svelte 5 Runes (Core Reactivity)
### The Rune System
Runes are compile-time macros prefixed with `$` that provide explicit, fine-grained reactivity.
| Rune | Purpose | Replaces |
| ----------- | --------------------- | --------------------------- |
| `$state` | Reactive state | `let` declarations |
| `$derived` | Computed values | `$:` reactive statements |
| `$effect` | Side effects | `$:` side effect statements |
| `$props` | Component props | `export let` |
| `$bindable` | Two-way binding props | `export let` with bind: |
### Basic Component Structure
```svelte
<script lang="ts">
// Props with TypeScript
interface Props {
title: string
count?: number
onUpdate?: (value: number) => void
}
let { title, count = 0, onUpdate }: Props = $props()
// Reactive state
let localCount = $state(count)
let items = $state<string[]>([])
// Derived values (auto-update when dependencies change)
let doubled = $derived(localCount * 2)
let total = $derived(items.reduce((sum, i) => sum + i.length, 0))
// Side effects
$effect(() => {
console.log(`Count changed to: ${localCount}`)
onUpdate?.(localCount)
})
// Methods
function increment() {
localCount++
}
</script>
<div class="component">
<h1>{title}</h1>
<p>Count: {localCount} (Doubled: {doubled})</p>
<button onclick={increment}>Increment</button>
</div>
<style>
.component {
padding: 1rem;
}
</style>
```
### State Patterns
```typescript
// Primitives
let count = $state(0);
let name = $state("");
// Objects (deeply reactive)
let user = $state({
name: "John",
email: "[email protected]",
preferences: { theme: "dark" },
});
// Arrays
let items = $state<Item[]>([]);
// Direct mutation works!
user.name = "Jane"; // Reactive
user.preferences.theme = "light"; // Reactive (deep)
items.push({ id: 1, name: "New" }); // Reactive
// Frozen state (shallow reactivity)
let frozenList = $state.frozen([1, 2, 3]);
```
### Derived Values
```typescript
// Simple derived
let doubled = $derived(count * 2);
// Complex derived (use $derived.by for multi-line)
let stats = $derived.by(() => {
const total = items.reduce((sum, i) => sum + i.value, 0);
const average = items.length ? total / items.length : 0;
return { total, average, count: items.length };
});
// Derived from multiple sources
let summary = $derived(`${user.name} has ${items.length} items`);
```
### Effects
```typescript
// Basic effect (runs when dependencies change)
$effect(() => {
console.log(`Count is now: ${count}`);
});
// Effect with cleanup
$effect(() => {
const interval = setInterval(() => {
count++;
}, 1000);
// Cleanup function (returned)
return () => clearInterval(interval);
});
// Pre-effect (runs before DOM updates)
$effect.pre(() => {
console.log("About to update DOM");
});
// Root effect (doesn't track dependencies)
$effect.root(() => {
// Manual dependency management
});
```
---
## Component Patterns
### Props with Defaults and Spreading
```svelte
<script lang="ts">
interface Props {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
children: import('svelte').Snippet
}
let {
variant = 'primary',
size = 'md',
disabled = false,
children,
...restProps
}: Props = $props()
</script>
<button
class="btn btn-{variant} btn-{size}"
{disabled}
{...restProps}
>
{@render children()}
</button>
```
### Two-Way Binding with $bindable
```svelte
<!-- Input.svelte -->
<script lang="ts">
interface Props {
value: string
}
let { value = $bindable() }: Props = $props()
</script>
<input bind:value />
<!-- Parent.svelte -->
<script lang="ts">
let name = $state('')
</script>
<Input bind:value={name} />
<p>Hello, {name}!</p>
```
### Snippets (Replacing Slots)
```svelte
<!-- Card.svelte -->
<script lang="ts">
import type { Snippet } from 'svelte'
interface Props {
title: string
children: Snippet
footer?: Snippet
}
let { title, children, footer }: Props = $props()
</script>
<div class="card">
<header>{title}</header>
<main>{@render children()}</main>
{#if footer}
<footer>{@render footer()}</footer>
{/if}
</div>
<!-- Usage -->
<Card title="My Card">
<p>Card content goes here</p>
{#snippet footer()}
<button>Action</button>
{/snippet}
</Card>
```
### Snippets with Parameters
```svelte
<!-- List.svelte -->
<script lang="ts" generics="T">
import type { Snippet } from 'svelte'
interface Props {
items: T[]
row: Snippet<[T, number]>
empty?: Snippet
}
let { items, row, empty }: Props = $props()
</script>
{#if items.length === 0}
{#if empty}
{@render empty()}
{:else}
<p>No items</p>
{/if}
{:else}
<ul>
{#each items as item, index}
<li>{@render row(item, index)}</li>
{/each}
</ul>
{/if}
<!-- Usage -->
<List items={users}>
{#snippet row(user, i)}
<span>{i + 1}. {user.name}</span>
{/snippet}
{#snippet empty()}
<p>No users found</p>
{/snippet}
</List>
```
---
## Shared State with .svelte.ts Files
### Creating Shared State
```typescript
// lib/stores/counter.svelte.ts
export function createCounter(initial = 0) {
let count = $state(initial);
return {
get count() {
return count;
},
increment() {
count++;
},
decrement() {
count--;
},
reset() {
count = initial;
},
};
}
// Singleton instance
export const counter = createCounter();
```
### Class-Based State
```typescript
// lib/stores/user.svelte.ts
export class UserStore {
user = $state<User | null>(null);
loading = $state(false);
error = $state<string | null>(null);
isLoggedIn = $derived(!!this.user);
async login(email: string, password: string) {
this.loading = true;
this.error = null;
try {
const response = await fetch("/api/auth/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: { "Content-Type": "application/json" },
});
if (!response.ok) throw new Error("Login failed");
this.user = await response.json();
} catch (e) {
this.error = e instanceof Error ? e.message : "Unknown error";
throw e;
} finally {
this.loading = false;
}
}
logout() {
this.user = null;
}
}
export const userStore = new UserStore();
```
### Using Shared State
```svelte
<script lang="ts">
import { counter } from '$lib/stores/counter.svelte'
import { userStore } from '$lib/stores/user.svelte'
</script>
<p>Count: {counter.count}</p>
<button onclick={counter.increment}>+</button>
{#if userStore.isLoggedIn}
<p>Welcome, {userStore.user?.name}</p>
<button onclick={() => userStore.logout()}>Logout</button>
{:else}
<button onclick={() => userStore.login('[email protected]', 'pass')}>
Login
</button>
{/if}
```
---
## SvelteKit (Full-Stack)
### Project Structure
```
sveltekit-app/
├── src/
│ ├── routes/ # File-based routing
│ │ ├── +page.svelte # /
│ │ ├── +page.server.ts # Server load function
│ │ ├── +layout.svelte # Root layout
│ │ ├── about/
│ │ │ └── +page.svelte # /about
│ │ ├── users/
│ │ │ ├── +page.svelte # /users
│ │ │ └── [id]/
│ │ │ ├── +page.svelte # /users/:id
│ │ │ └── +page.server.ts
│ │ └── api/
│ │ └── users/
│ │ └── +server.ts #Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.