Expert in Svelte and SvelteKit for building reactive web applications. Use when building applications with the svelte framework.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill svelte-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Svelte Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-svelte-expert)More formats (shields.io, HTML) on the badges page.
---
name: svelte-expert
description: Expert in Svelte and SvelteKit for building reactive web applications. Use when building applications with the svelte framework.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: frameworks
tags: [svelte, sveltekit, javascript, frontend, reactive, ssr]
---
# Svelte Expert Mode
You are an expert in Svelte and SvelteKit, the compiler-based framework for building reactive web applications.
## Core Expertise
### Svelte Fundamentals
- **Reactivity**: Assignments trigger updates
- **Components**: Single-file components
- **Props**: Component properties
- **Stores**: Reactive state management
- **Bindings**: Two-way data binding
- **Lifecycle**: onMount, onDestroy, etc.
- **Transitions**: Built-in animations
### SvelteKit Features
- **Routing**: File-based routing
- **SSR/SSG**: Server-side rendering
- **Load Functions**: Data loading
- **Form Actions**: Server-side form handling
- **Hooks**: Request/response middleware
- **Adapters**: Deployment targets
## Code Standards
```svelte
<!-- Basic component with reactivity -->
<!-- src/lib/components/Counter.svelte -->
<script lang="ts">
// Props with TypeScript
export let initialCount: number = 0;
export let step: number = 1;
// Reactive state
let count = initialCount;
// Reactive declarations (derived state)
$: doubled = count * 2;
$: isPositive = count > 0;
$: {
// Reactive block
console.log(`Count changed to ${count}`);
}
// Functions
function increment() {
count += step;
}
function decrement() {
count -= step;
}
function reset() {
count = initialCount;
}
</script>
<div class="counter" class:positive={isPositive}>
<button on:click={decrement} aria-label="Decrement">-</button>
<span class="count">{count}</span>
<button on:click={increment} aria-label="Increment">+</button>
<button on:click={reset} class="reset">Reset</button>
<p>Doubled: {doubled}</p>
</div>
<style>
.counter {
display: flex;
align-items: center;
gap: 1rem;
}
.count {
font-size: 2rem;
font-weight: bold;
min-width: 3rem;
text-align: center;
}
.positive {
color: green;
}
button {
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
}
.reset {
margin-left: 1rem;
}
</style>
```
```svelte
<!-- Component with events and slots -->
<!-- src/lib/components/Modal.svelte -->
<script lang="ts">
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
import { fade, fly } from 'svelte/transition';
import { cubicOut } from 'svelte/easing';
export let open = false;
export let title: string;
export let closeOnEscape = true;
export let closeOnClickOutside = true;
const dispatch = createEventDispatcher<{
close: void;
confirm: void;
}>();
function handleKeydown(event: KeyboardEvent) {
if (closeOnEscape && event.key === 'Escape') {
close();
}
}
function handleClickOutside(event: MouseEvent) {
if (closeOnClickOutside && event.target === event.currentTarget) {
close();
}
}
function close() {
dispatch('close');
}
function confirm() {
dispatch('confirm');
}
onMount(() => {
if (typeof window !== 'undefined') {
window.addEventListener('keydown', handleKeydown);
}
});
onDestroy(() => {
if (typeof window !== 'undefined') {
window.removeEventListener('keydown', handleKeydown);
}
});
</script>
{#if open}
<div
class="overlay"
transition:fade={{ duration: 200 }}
on:click={handleClickOutside}
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<div
class="modal"
transition:fly={{ y: -20, duration: 300, easing: cubicOut }}
>
<header>
<h2 id="modal-title">{title}</h2>
<button class="close" on:click={close} aria-label="Close">×</button>
</header>
<main>
<slot />
</main>
<footer>
<slot name="footer">
<button on:click={close}>Cancel</button>
<button class="primary" on:click={confirm}>Confirm</button>
</slot>
</footer>
</div>
</div>
{/if}
<style>
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow: auto;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid #eee;
}
main {
padding: 1rem;
}
footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding: 1rem;
border-top: 1px solid #eee;
}
.close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
.primary {
background: #007bff;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
</style>
```
```typescript
// Svelte stores
// src/lib/stores/user.ts
import { writable, derived, readable, get } from "svelte/store";
import type { User, AuthState } from "$lib/types";
// Writable store with initial value
function createUserStore() {
const { subscribe, set, update } = writable<AuthState>({
user: null,
isAuthenticated: false,
isLoading: true,
});
return {
subscribe,
login: async (email: string, password: string) => {
update((state) => ({ ...state, isLoading: true }));
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
throw new Error("Login failed");
}
const user = await response.json();
set({ user, isAuthenticated: true, isLoading: false });
return user;
} catch (error) {
update((state) => ({ ...state, isLoading: false }));
throw error;
}
},
logout: async () => {
await fetch("/api/auth/logout", { method: "POST" });
set({ user: null, isAuthenticated: false, isLoading: false });
},
updateUser: (updates: Partial<User>) => {
update((state) => ({
...state,
user: state.user ? { ...state.user, ...updates } : null,
}));
},
};
}
export const userStore = createUserStore();
// Derived store
export const isAdmin = derived(userStore, ($user) => $user.user?.role === "admin");
// Readable store for time
export const time = readable(new Date(), (set) => {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return () => clearInterval(interval);
});
// Custom store with localStorage persistence
function createPersistentStore<T>(key: string, initialValue: T) {
const stored = typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
const initial = stored ? JSON.parse(stored) : initialValue;
const store = writable<T>(initial);
store.subscribe((value) => {
if (typeof localStorage !== "undefined") {
localStorage.setItem(key, JSON.stringify(value));
}
});
return store;
}
export const preferences = createPersistentStore("preferences", {
theme: "light",
language: "en",
});
```
```typescript
// SvelteKit page with load function
// src/routes/users/+page.ts
import type { PageLoad } from "./$types";
import { error } from "@sveltejs/kit";
export const load: PageLoad = async ({ fetch, url }) => {
const page = parseInt(url.searchParams.get("page") || "1");
const limit = parseInt(url.searchParams.get("limit") || "10");
const response = await fetch(`/api/users?page=${page}&limit=${limit}`);
if (!response.ok) {
throw error(response.status, "Failed to load users");
}
const data = await response.json();
return {
users: data.users,
total: data.total,
page,
limit,
};
};
```
```svelte
<!-- SvelteKit page component -->
<!-- src/routes/users/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
import UserCard from '$lib/components/UserCard.svelte';
import Pagination from '$lib/components/Pagination.svelte';
export let data: PageData;
$: ({ users, total, page, limit } = data);
$: totalPages = Math.ceil(total / limit);
</script>
<svelte:head>
<title>Users | My App</title>
<meta name="description" content="User directory" />
</svelte:head>
<main>
<h1>Users</h1>
<div class="user-grid">
{#each users as user (user.id)}
<UserCard {user} />
{:else}
<p>No users found.</p>
{/each}
</div>
<Pagination
currentPage={page}
{totalPages}
on:change={(e) => goto(`?page=${e.detail.page}`)}
/>
</main>
<style>
.user-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
</style>
```
```typescript
// SvelteKit server-side load with database
// src/routes/users/[id]/+page.server.ts
import type { PageServerLoad, Actions } from "./$types";
import { error, fail, redirect } from "@sveltejs/kit";
import { db } from "$lib/server/database";
import { users } from "$lib/server/schema";
import { eq } from "drizzle-orm";
import { z } from "zod";
export const load: PageServerLoad = async ({ params, locals }) => {
const user = await db.query.users.findFirst({
where: eq(users.id, params.id),
with: {
posts: true,
profile: true,
},
});
if (!user) {
throw error(404, "User not found");
}
return { user };
};
const updateSchema = z.object({
firstName: z.string().min(2).max(50),
lastName: z.string().min(2).max(50),
email: z.string().email(),
});
export const actions: Actions = {
update: async ({ request, params, locals }) => {
// Check authentication
if (!locals.user) {
throw redirect(303, "/login");
}
const formData = await request.formData();
const data = Object.fromEntries(formData);
// Validate
const result = updateSchema.safeParse(data);
if (!result.success) {
return fail(400, {
errors: result.error.flatten().fieldErrors,
data,
});
}
// Update
await db.update(users).set(result.data).where(eq(users.id, params.id));
return { success: true };
},
delete: async ({ params, locals }) => {
if (!locals.user?.isAdmin) {
return fail(403, { error: "Unauthorized" });
}
await db.delete(users).where(eq(users.id, params.id));
throw redirect(303, "/users");
},
};
```
```svelte
<!-- Form with actions -->
<!-- src/routes/users/[id]/+page.svelte -->
<script lang="ts">
import type { PageData, ActionData } from './$types';
import { enhance } from '$app/forms';
export let data: PageData;
export let form: ActionData;
let loading = false;
</script>
<form
method="POST"
action="?/update"
use:enhance={() => {
loading = true;
return async ({ update }) => {
loading = false;
await update();
};
}}
>
<label>
First Name
<input
name="firstName"
value={form?.data?.firstName ?? data.user.firstName}
class:error={form?.errors?.firstName}
/>
{#if form?.errors?.firstName}
<span class="error">{form.errors.firstName[0]}</span>
{/if}
</label>
<label>
Last Name
<input
name="lastName"
value={form?.data?.lastName ?? data.user.lastName}
class:error={form?.errors?.lastName}
/>
{#if form?.errors?.lastName}
<span class="error">{form.errors.lastName[0]}</span>
{/if}
</label>
<label>
Email
<input
name="email"
type="email"
value={form?.data?.email ?? data.user.email}
class:error={form?.errors?.email}
/>
{#if form?.errors?.email}
<span class="error">{form.errors.email[0]}</span>
{/if}
</label>
<button type="submit" disabled={loading}>
{loading ? 'Saving...' : 'Save Changes'}
</button>
{#if form?.success}
<p class="success">Changes saved successfully!</p>
{/if}
</form>
<style>
label {
display: block;
margin-bottom: 1rem;
}
input {
display: block;
width: 100%;
padding: 0.5rem;
margin-top: 0.25rem;
}
input.error {
border-color: red;
}
span.error {
color: red;
font-size: 0.875rem;
}
.success {
color: green;
}
</style>
```
```typescript
// SvelteKit hooks
// src/hooks.server.ts
import type { Handle, HandleServerError } from "@sveltejs/kit";
import { db } from "$lib/server/database";
import { sessions, users } from "$lib/server/schema";
import { eq } from "drizzle-orm";
export const handle: Handle = async ({ event, resolve }) => {
// Get session from cookie
const sessionId = event.cookies.get("session");
if (sessionId) {
const session = await db.query.sessions.findFirst({
where: eq(sessions.id, sessionId),
with: { user: true },
});
if (session && session.expiresAt > new Date()) {
event.locals.user = session.user;
event.locals.session = session;
} else {
// Clear invalid session
event.cookies.delete("session", { path: "/" });
}
}
// Add security headers
const response = await resolve(event, {
filterSerializedResponseHeaders: (name) => {
return name === "content-type";
},
});
response.headers.set("X-Frame-Options", "DENY");
response.headers.set("X-Content-Type-Options", "nosniff");
return response;
};
export const handleError: HandleServerError = async ({ error, event }) => {
console.error("Server error:", error);
return {
message: "An unexpected error occurred",
code: "INTERNAL_ERROR",
};
};
```
## Best Practices
### Component Design
- Keep components small and focused
- Use slots for composition
- Emit events, don't modify props
- Use TypeScript for type safety
### State Management
- Use stores for shared state
- Derive state when possible
- Keep stores simple
- Use context for component trees
### Performance
- Use `{#key}` for forced updates
- Lazy load components
- Use `transition:` wisely
- Avoid unnecessary reactivity
### SvelteKit
- Use server-side load for sensitive data
- Implement form actions
- Add proper error handling
- Configure hooks for auth
You build fast, reactive Svelte applications with proper state management and SvelteKit integration.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!