SV

svelte5-development

Provides guidance on Svelte 5 features, specifically runes, reactivity, and SvelteKit application architecture.

Install

mkdir -p .claude/skills/svelte5-development && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/274" && unzip -o skill.zip -d .claude/skills/svelte5-development && rm skill.zip

Installs to .claude/skills/svelte5-development

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Comprehensive Svelte 5 and SvelteKit development guidance. Use this skill when building Svelte components, working with runes, or developing SvelteKit applications. Covers reactive patterns, component architecture, routing, and data loading.
241 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Implement reactive state with runes
  • Create computed values from state dependencies
  • Design component structures using $state.raw
  • Bridge server-side logic with SvelteKit

How it works

Applies Svelte 5 reactivity rules to transform mutable state into reactive proxy-based data structures.

Inputs & outputs

You give it
Component logic requirement or state management problem
You get back
Code snippet utilizing Svelte 5 runes and patterns

When to use svelte5-development

  • Managing reactive state with runes
  • Building SvelteKit components
  • Implementing server-side data fetching
  • Optimizing performance with raw state

About this skill

This skill provides guidance for Svelte 5 and SvelteKit development, covering runes, component patterns, routing, and common pitfalls.

Svelte 5 Runes - Core Reactivity

$state - Reactive State

Creates reactive state that updates the UI when changed.

<script>
	let count = $state(0);
	let user = $state({ name: 'Alice', age: 30 });
</script>

<button onclick={() => count++}>Clicks: {count}</button>
<button onclick={() => user.age++}>Age: {user.age}</button>

Deep Reactivity: Objects and arrays become deeply reactive proxies. Mutations trigger updates:

let todos = $state([{ done: false, text: 'learn svelte' }]);
todos[0].done = true; // triggers update
todos.push({ done: false, text: 'build app' }); // triggers update

Classes: Use $state in class fields:

class Todo {
	done = $state(false);
	constructor(text) {
		this.text = $state(text);
	}
	reset = () => {
		this.text = '';
		this.done = false;
	}
}

Important: When you destructure reactive state, references are NOT reactive:

let { done, text } = todos[0];
todos[0].done = true; // `done` variable won't update

$state.raw: Use for non-reactive objects (performance optimization):

let data = $state.raw({ large: 'dataset' });
data.large = 'new value'; // no effect, must reassign entire object
data = { large: 'new value' }; // this works

$derived - Computed Values

Creates values that automatically update when dependencies change.

<script>
	let count = $state(0);
	let doubled = $derived(count * 2);
	let tripled = $derived(count * 3);
</script>

<p>{count} × 2 = {doubled}</p>
<p>{count} × 3 = {tripled}</p>

For complex logic, use $derived.by:

let numbers = $state([1, 2, 3]);
let total = $derived.by(() => {
	let sum = 0;
	for (const n of numbers) sum += n;
	return sum;
});

Critical Rule: NEVER update state inside $derived - it should be side-effect free.

Overriding deriveds (Svelte 5.25+): Useful for optimistic UI:

let likes = $derived(post.likes);

async function onclick() {
	likes += 1; // optimistic update
	try {
		await likePost();
	} catch {
		likes -= 1; // rollback on error
	}
}

$effect - Side Effects

Runs when state changes. Use for DOM manipulation, third-party libraries, analytics.

<script>
	let size = $state(50);
	let canvas;

	$effect(() => {
		const ctx = canvas.getContext('2d');
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		// reruns when `size` changes
		ctx.fillRect(0, 0, size, size);
	});
</script>

<canvas bind:this={canvas} width="100" height="100"></canvas>

Lifecycle: Effects run after component mounts and after state changes (in microtask).

Teardown functions: Return a function to clean up:

$effect(() => {
	const interval = setInterval(() => count++, 1000);
	return () => clearInterval(interval); // cleanup
});

Dependencies: Automatically tracks any $state/$derived read synchronously. Async reads (after await) are NOT tracked:

$effect(() => {
	context.fillStyle = color; // tracked
	setTimeout(() => {
		context.fillRect(0, 0, size, size); // size NOT tracked!
	}, 0);
});

Conditional dependencies: Only depends on values read in the last run:

$effect(() => {
	if (condition) {
		confetti({ colors: [color] }); // only depends on color if condition is true
	}
});

$effect.pre: Runs BEFORE DOM updates (rare, for things like autoscroll).

CRITICAL - When NOT to use $effect:

  • ❌ Don't synchronize state (use $derived instead)
  • ❌ Don't use for computed values
  • ✅ DO use for: canvas drawing, third-party libs, analytics, intervals, DOM manipulation
<!-- ❌ BAD - Don't do this -->
<script>
	let count = $state(0);
	let doubled = $state();
	$effect(() => {
		doubled = count * 2; // WRONG! Use $derived
	});
</script>

<!-- ✅ GOOD - Do this -->
<script>
	let count = $state(0);
	let doubled = $derived(count * 2);
</script>

$props - Component Props

Receives data from parent components.

<!-- Parent.svelte -->
<Child message="hello" count={42} />

<!-- Child.svelte -->
<script>
	let { message, count = 0 } = $props(); // destructuring with defaults
</script>

<p>{message} - {count}</p>

Renaming props (for reserved words or invalid identifiers):

let { super: trouper = 'default' } = $props();

Rest props:

let { a, b, ...others } = $props();

Type safety (TypeScript):

<script lang="ts">
	let { message }: { message: string } = $props();
	// or
	interface Props {
		message: string;
		count?: number;
	}
	let { message, count = 0 }: Props = $props();
</script>

Important: Props update reactively, but you should NOT mutate them (unless $bindable).

$bindable - Two-Way Binding

Allows child components to update parent state.

<!-- FancyInput.svelte -->
<script>
	let { value = $bindable(), ...props } = $props();
</script>

<input bind:value {...props} />

<!-- Parent.svelte -->
<script>
	import FancyInput from './FancyInput.svelte';
	let message = $state('hello');
</script>

<FancyInput bind:value={message} />
<p>{message}</p>

Fallback values:

let { value = $bindable('default value') } = $props();

Use sparingly: Most components should use callback props instead of $bindable.

Common Patterns and Pitfalls

Effect vs Derived

<script>
	let a = $state(1);
	let b = $state(2);

	// ✅ GOOD - Use $derived for computed values
	let sum = $derived(a + b);

	// ❌ BAD - Don't use $effect for this
	let sum2 = $state(0);
	$effect(() => {
		sum2 = a + b; // WRONG!
	});

	// ✅ GOOD - Use $effect for side effects only
	$effect(() => {
		console.log('Sum changed:', sum);
		analytics.track('calculation', { sum });
	});
</script>

Navigation with Remote Functions

When using SvelteKit's remoteFunctions feature, standard <a href> links don't work for client-side navigation.

<script>
	import { goto } from '$app/navigation';
</script>

<!-- ❌ DON'T use regular links with remote functions -->
<a href="/songs/{id}/edit">{title}</a>

<!-- ✅ DO use goto() -->
<button onclick={() => goto(`/songs/${id}/edit`)}>{title}</button>

Style buttons as links:

.link-button {
	background: none;
	border: none;
	padding: 0;
	color: inherit;
	cursor: pointer;
	text-decoration: underline;
}

Async Operations and Form Initialization

<script>
	let song = $state({ current: null });
	let title = $state('');
	let initialized = $state(false);

	// ✅ GOOD - Use $effect for async initialization
	$effect(() => {
		if (song.current && !initialized) {
			title = song.current.title || '';
			initialized = true;
		}
	});
</script>

SvelteKit Routing

File Structure

  • +page.svelte - Page component
  • +page.js - Universal load (runs server + client)
  • +page.server.js - Server-only load
  • +layout.svelte - Layout component (wraps pages)
  • +layout.js / +layout.server.js - Layout load functions
  • +error.svelte - Error page
  • +server.js - API endpoints

Dynamic Routes

  • [slug] - Single parameter
  • [...rest] - Rest parameter (catches multiple segments)
  • [[optional]] - Optional parameter

Example: src/routes/blog/[slug]/+page.svelte matches /blog/hello-world

Loading Data

Page Load (+page.js or +page.server.js):

/** @type {import('./$types').PageLoad} */
export function load({ params, url, fetch }) {
	return {
		post: {
			title: `Post ${params.slug}`,
			content: 'Content here'
		}
	};
}

Layout Load (+layout.server.js):

/** @type {import('./$types').LayoutServerLoad} */
export async function load() {
	return {
		sections: [
			{ slug: 'profile', title: 'Profile' },
			{ slug: 'settings', title: 'Settings' }
		]
	};
}

Accessing Data in Components:

<script>
	/** @type {import('./$types').PageProps} */
	let { data } = $props();
</script>

<h1>{data.post.title}</h1>

Parent Data Access:

export async function load({ parent }) {
	const { user } = await parent();
	return { username: user.name };
}

Universal vs Server Load

Use +page.js (Universal) when:

  • Fetching from public APIs
  • No private credentials needed
  • Returning custom classes or constructors
  • Running same logic server + client

Use +page.server.js (Server) when:

  • Accessing database directly
  • Using private environment variables
  • Reading from filesystem
  • Need to serialize data for client

Server load returns must be serializable (JSON + Date, Map, Set, RegExp, BigInt).

Form Actions

// +page.server.js
export const actions = {
	default: async ({ request }) => {
		const data = await request.formData();
		const email = data.get('email');
		// process form...
		return { success: true };
	}
};
<!-- +page.svelte -->
<script>
	/** @type {import('./$types').PageProps} */
	let { form } = $props();
</script>

{#if form?.success}
	<p>Success!</p>
{/if}

<form method="POST">
	<input name="email" type="email" />
	<button>Submit</button>
</form>

Real-time Updates (Server-Sent Events)

Server (+server.js):

export function GET() {
	const stream = new ReadableStream({
		start(controller) {
			const encoder = new TextEncoder();
			const send = (data) => {
				controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`));
			};
			// Send updates...
			setInterval(() => send({ time: Date.now() }), 1000);
		}
	});

	return new Response(stream, {
		headers: {
			'Content-Type': 'text/event-stream',
			'Cache-Control': 'no-cache'
		}
	});
}

Client:

<script>
	let data = $state({ time: 0 });

	$effect(() => {
		const source = new EventSource('/updates');
		source.onmessage = (e) => {
			data = JSON.parse(e.data);
		};
		return () => source.close();
	});
</script>

Environment Variables

Public (exposed to client):

import { PUBLIC_STATION_NAME } from '$env/static/public';

**Privat


Content truncated.

When not to use it

  • Legacy Svelte 4 projects
  • Non-reactive UI frameworks
  • High-compute server logic better suited for backend Python/Node

Limitations

  • Deep reactivity requires specific reassignment patterns
  • Incorrect use of runes can cause silent UI synchronization failures
  • Runes are syntax-specific to Svelte 5+

How it compares

It focuses on the specific semantics of Svelte 5 runes ($state, $derived) rather than general Svelte component syntax.

Compared to similar skills

svelte5-development side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
svelte5-development (this skill)148moNo flagsIntermediate
svelte-ui-design239moNo flagsIntermediate
skeleton-svelte159moNo flagsBeginner
svelte-expert119moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

svelte-ui-design

XIYO

ALWAYS use this skill for ANY Svelte component styling, design, or UI work. Svelte 5 UI design system using Tailwind CSS 4, Skeleton Labs design tokens/presets/Tailwind Components, and Bits UI headless components. Covers class composition, color systems, interactive components, forms, overlays, and all visual design.

23136

skeleton-svelte

martinemde

Use this skill when working with Skeleton UI components in Svelte projects. It provides guidelines for Skeleton's component composition pattern, theme-aware color system, design presets, and layout patterns. Trigger when building UI components, styling elements, creating layouts, or working with Skeleton-specific features in Svelte 5 and SvelteKit 2+ projects.

15113

svelte-expert

Raudbjorn

Expert Svelte/SvelteKit development assistant for building components, utilities, and applications. Use when creating Svelte components, SvelteKit applications, implementing reactive patterns, handling state management, working with stores, transitions, animations, or any Svelte/SvelteKit development task. Includes comprehensive documentation access, code validation with svelte-autofixer, and playground link generation.

11107

sveltekit-structure

spences10

SvelteKit structure guidance. Use for routing, layouts, error handling, and SSR. Covers file naming (+page vs +layout vs +server), nested layouts, error boundaries, and hydration.

782

tanstack-form

exceptionless

TanStack Form with Zod validation in Svelte 5. Form state management, field validation, error handling, and ProblemDetails integration. Keywords: TanStack Form, createForm, Field, form validation, zod schema, form errors, onSubmit, onSubmitAsync, problemDetailsToFormErrors

1670

web-component-design

wshobson

Master React, Vue, and Svelte component patterns including CSS-in-JS, composition strategies, and reusable component architecture. Use when building UI component libraries, designing component APIs, or implementing frontend design systems.

548

Search skills

Search the agent skills registry