svelte5-development

Svelte 5 Development Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "svelte5-development" with this command: npx skills add autumnsgrove/groveengine/autumnsgrove-groveengine-svelte5-development

Svelte 5 Development Skill

When to Activate

Activate this skill when:

  • Creating Svelte 5 components

  • Working with SvelteKit routing

  • Implementing runes ($state, $derived, $effect)

  • Building forms with actions

  • Setting up SvelteKit projects

Quick Commands

npx sv create my-app # Create SvelteKit project cd my-app && pnpm install pnpm dev # Start dev server (localhost:5173) pnpm build # Build for production

Runes Quick Reference

Rune Purpose Example

$state

Reactive state let count = $state(0)

$derived

Computed values let doubled = $derived(count * 2)

$effect

Side effects $effect(() => console.log(count))

$props

Component props let { name } = $props()

$bindable

Two-way binding let { value = $bindable() } = $props()

Reactive State ($state)

<script> let count = $state(0); let user = $state({ name: "Alice", age: 30 }); let items = $state(["apple", "banana"]); </script>

<button onclick={() => count++}> Clicked {count} times </button>

<button onclick={() => user.age++}> {user.name} is {user.age} </button>

Deep reactivity: Objects and arrays update automatically on mutation.

Computed Values ($derived)

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

// For complex computations
let summary = $derived.by(() => {
	const total = items.length;
	const done = items.filter((i) => i.done).length;
	return `${done}/${total}`;
});

</script>

Side Effects ($effect)

<script> let count = $state(0);

$effect(() => {
	console.log(`Count is ${count}`);
	document.title = `Count: ${count}`;

	// Cleanup function
	return () => {
		console.log("Cleanup");
	};
});

</script>

Component Props ($props)

<!-- Button.svelte --> <script> let { label, disabled = false, onclick } = $props(); </script>

<button {disabled} {onclick}>{label}</button>

TypeScript Props

<script lang="ts"> interface Props { label: string; disabled?: boolean; onclick?: () => void; }

let { label, disabled = false, onclick }: Props = $props();

</script>

SvelteKit File Conventions

File Purpose

+page.svelte

Page component

+page.server.js

Server-only load/actions

+layout.svelte

Shared layout

+server.js

API endpoints

+error.svelte

Error boundary

Data Loading

// src/routes/posts/+page.server.js export async function load({ fetch }) { const response = await fetch("/api/posts"); return { posts: await response.json() }; }

<!-- src/routes/posts/+page.svelte --> <script> let { data } = $props(); </script>

{#each data.posts as post} <article> <h2>{post.title}</h2> </article> {/each}

Form Actions

Type-Safe Form Validation (Rootwork Pattern)

Use parseFormData() for type-safe form handling at trust boundaries:

// src/routes/login/+page.server.ts import { fail, redirect } from "@sveltejs/kit"; import { parseFormData } from "@autumnsgrove/lattice/server"; import { z } from "zod";

const LoginSchema = z.object({ email: z.string().email("Valid email required"), password: z.string().min(8, "Password must be at least 8 characters"), });

export const actions = { default: async ({ request, cookies }) => { const formData = await request.formData(); const result = parseFormData(formData, LoginSchema);

	if (!result.success) {
		const firstError = Object.values(result.errors).flat()[0];
		return fail(400, { error: firstError || "Invalid input" });
	}

	const { email, password } = result.data;

	// Authenticate with validated, typed data
	const token = await authenticate(email, password);
	if (!token) {
		return fail(401, { error: "Invalid credentials" });
	}

	cookies.set("session", token, { path: "/" });
	throw redirect(303, "/dashboard");
},

};

Benefits:

  • Type-safe: result.data is fully typed as LoginSchema

  • Structured errors: result.errors is a map of field → messages

  • No as casts at trust boundaries

<!-- +page.svelte --> <script> import { enhance } from "$app/forms"; let { form } = $props(); </script>

<form method="POST" use:enhance> <input name="email" value={form?.email ?? ""} /> {#if form?.missing} <p class="error">Email required</p> {/if} <button>Submit</button> </form>

API Routes

// src/routes/api/posts/+server.js import { json } from "@sveltejs/kit";

export async function GET({ url }) { const posts = await getPosts(); return json(posts); }

export async function POST({ request }) { const data = await request.json(); const post = await createPost(data); return json(post, { status: 201 }); }

Common Pitfalls

Destructuring Breaks Reactivity

// ❌ Bad let { count } = $state({ count: 0 });

// ✅ Good let state = $state({ count: 0 }); state.count++;

Missing Keys in Each

<!-- ❌ Bad --> {#each items as item}

<!-- ✅ Good --> {#each items as item (item.id)}

Use Progressive Enhancement

<script> import { enhance } from '$app/forms'; </script>

<form method="POST" use:enhance>

Error Feedback (Signpost + Toast)

Toast is the primary client-side feedback for user actions:

import { toast } from "@autumnsgrove/lattice/ui";

// After successful action toast.success("Post published!");

// After failed action toast.error(err instanceof Error ? err.message : "Something went wrong");

// Async operations toast.promise(apiRequest("/api/export", { method: "POST" }), { loading: "Exporting...", success: "Done!", error: "Export failed.", });

// Multi-step flows const id = toast.loading("Saving..."); // ... later toast.dismiss(id); toast.success("Saved!");

When NOT to use toast: form validation (use fail()

  • inline errors), page load failures (+error.svelte ), persistent notices (use GroveMessages).

Server-side errors use Signpost codes:

import { API_ERRORS, buildErrorJson, throwGroveError, logGroveError, } from "@autumnsgrove/lattice/errors";

// API route: return structured error return json(buildErrorJson(API_ERRORS.RESOURCE_NOT_FOUND), { status: 404 });

// Page load: throw to +error.svelte throwGroveError(404, SITE_ERRORS.PAGE_NOT_FOUND, "Engine");

Type-Safe Error Handling (Rootwork Guards)

Use isRedirect() and isHttpError() to safely handle caught exceptions in form actions:

import { isRedirect, isHttpError } from "@autumnsgrove/lattice/server"; import { fail } from "@sveltejs/kit";

export const actions = { default: async ({ request }) => { try { const formData = await request.formData(); const result = parseFormData(formData, MySchema);

		if (!result.success) {
			return fail(400, { error: "Validation failed" });
		}

		// Process data
		const response = await processData(result.data);
		throw redirect(303, "/success");
	} catch (err) {
		// Redirects and HTTP errors must be re-thrown
		if (isRedirect(err)) throw err;
		if (isHttpError(err)) return fail(err.status, { error: err.body.message });

		// Unexpected errors
		console.error("Unexpected error:", err);
		return fail(500, { error: "Something went wrong" });
	}
},

};

See AgentUsage/error_handling.md and AgentUsage/rootwork_type_safety.md for the full reference.

Project Structure

src/ ├── lib/ │ ├── components/ │ └── server/ ├── routes/ │ ├── +layout.svelte │ ├── +page.svelte │ └── api/ ├── app.html └── hooks.server.js

Grove-Specific: GroveTerm Components

When building Grove UI that includes nature-themed terminology, always use the GroveTerm component suite instead of hardcoding terms. This respects users' Grove Mode setting (standard terms by default, opt-in to Grove vocabulary).

<script lang="ts"> import { GroveTerm, GroveSwap, GroveText } from "@autumnsgrove/lattice/ui"; import groveTermManifest from "$lib/data/grove-term-manifest.json"; </script>

<!-- Interactive term with popup definition --> <GroveTerm term="bloom" manifest={groveTermManifest} />

<!-- Silent swap (no popup, no underline) --> <GroveSwap term="arbor" manifest={groveTermManifest} />

<!-- Parse [[term]] syntax in data strings --> <GroveText content="Your [[bloom|posts]] live in your [[garden|blog]]." manifest={groveTermManifest} />

See libs/engine/src/lib/ui/components/ui/groveterm/ for component source and chameleon-adapt skill for full UI design guidance.

Related Resources

See AgentUsage/svelte5_guide.md for complete documentation including:

  • Advanced rune patterns

  • Snippets for reusable markup

  • Performance optimization

  • TypeScript integration

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-quality

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python-testing

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

git-workflows

No summary provided by upstream source.

Repository SourceNeeds Review