| name | dev |
| description | Elite Svelte and TypeScript development skill for top 0.001% developers. Focuses on creating clean, modular, reusable code with exceptional architecture, type safety, and performance. Use when building Svelte applications, creating components, or refactoring existing code for maximum maintainability and scalability. Use when this capability is needed. |
| metadata | {"author":"gettraek"} |
Svelte Elite Developer
A skill for writing production-grade Svelte and TypeScript code that exemplifies clean architecture, modularity, and reusability.
Core Principles
1. Type Safety First
- Strict TypeScript everywhere: Enable
strict: true in tsconfig.json
- No implicit any: Every value has an explicit, meaningful type
- Generic utilities: Create reusable type utilities for common patterns
- Type inference: Leverage TypeScript's inference but guide it with explicit types at boundaries
- Discriminated unions: Use for state management and conditional rendering
2. Component Architecture
- Single Responsibility: Each component does one thing exceptionally well
- Composition over configuration: Build complex UIs from simple, composable pieces
- Prop drilling prevention: Use context API and stores appropriately
- Container/Presentational: Separate logic (container) from UI (presentational)
- Slot-driven flexibility: Design components with slots for maximum reusability
3. State Management Strategy
- Derived stores: Compute values reactively rather than duplicating state
- Custom stores: Encapsulate business logic in dedicated store files
- Store composition: Combine stores to create higher-level abstractions
- Immutable updates: Always return new objects/arrays from store update functions
- Type-safe stores: Every store has explicit TypeScript interfaces
4. Code Organization
src/
├── lib/
│ ├── components/
│ │ ├── ui/ # Pure presentational components
│ │ ├── domain/ # Business-specific components
│ │ └── layouts/ # Layout components
│ ├── stores/ # Svelte stores with business logic
│ ├── actions/ # Svelte actions (reusable directives)
│ ├── utils/ # Pure utility functions
│ ├── types/ # TypeScript type definitions
│ ├── services/ # API clients, external integrations
│ └── constants/ # App-wide constants
├── routes/ # SvelteKit routes
└── app.d.ts # Global type augmentation
Best Practices
Component Design Patterns
Props Interface Pattern
<script lang="ts">
interface Props {
items: readonly Item[];
onSelect?: (item: Item) => void;
disabled?: boolean;
class?: string;
}
let {
items,
onSelect,
disabled = false,
class: className = ''
}: Props = $props();
</script>
Slot Props Pattern
<script lang="ts" generics="T">
interface Props<T> {
items: readonly T[];
renderKey: (item: T) => string | number;
}
let { items, renderKey }: Props<T> = $props();
</script>
{#each items as item (renderKey(item))}
<slot {item} />
{/each}
Event Handler Pattern
<script lang="ts">
import { createEventDispatcher } from 'svelte';
type Events = {
select: { id: string; value: unknown };
cancel: void;
};
const dispatch = createEventDispatcher<Events>();
function handleSelect(id: string, value: unknown) {
dispatch('select', { id, value });
}
</script>
Store Patterns
Custom Store with Encapsulation
import { writable, type Readable } from 'svelte/store';
interface CounterState {
readonly count: number;
readonly history: readonly number[];
}
interface CounterStore extends Readable<CounterState> {
increment: () => void;
decrement: () => void;
reset: () => void;
setCount: (value: number) => void;
}
function createCounter(initialValue = 0): CounterStore {
const { subscribe, update } = writable<CounterState>({
count: initialValue,
history: [initialValue]
});
return {
subscribe,
increment: () =>
update((state) => ({
count: state.count + 1,
: [...state., state. + ]
})),
:
( ({
: state. - ,
: [...state., state. - ]
})),
:
( ({
: initialValue,
: [initialValue]
})),
:
( ({
: value,
: [...state., value]
}))
};
}
counter = ();
Derived Store Pattern
import { derived, type Readable } from 'svelte/store';
import { users } from './users';
import { filters } from './filters';
interface FilteredUser {
readonly id: string;
readonly name: string;
readonly active: boolean;
}
export const filteredUsers: Readable<readonly FilteredUser[]> = derived(
[users, filters],
([$users, $filters]) => {
return $users.filter((user) => {
if ($filters.activeOnly && !user.active) return false;
if (
$filters.searchTerm &&
!user.name.toLowerCase().includes($filters.searchTerm.toLowerCase())
) {
return false;
}
return true;
});
}
);
Action Patterns
Reusable Action with TypeScript
import type { Action } from 'svelte/action';
interface ClickOutsideParams {
enabled?: boolean;
callback: () => void;
}
export const clickOutside: Action<HTMLElement, ClickOutsideParams> = (node, params) => {
const { enabled = true, callback } = params;
function handleClick(event: MouseEvent) {
if (!enabled) return;
if (node && !node.contains(event.target as Node)) {
callback();
}
}
document.addEventListener('click', handleClick, true);
return {
update(newParams) {
params = newParams;
},
destroy() {
document.removeEventListener('click', handleClick, true);
}
};
};
Type Utility Patterns
Common Type Utilities
export type RequireKeys<T, K extends keyof T> = T & Required<Pick<T, K>>;
export type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export type ArrayElement<T> = T extends readonly (infer E)[] ? E : never;
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
export type DiscriminatedUnion<T extends Record<string, unknown>> = {
[K in keyof T]: { type: K; payload: T[K] };
}[keyof T];
Performance Optimization
Memoization Pattern
<script lang="ts">
import { derived } from 'svelte/store';
interface Props {
items: readonly Item[];
computeExpensive: (items: readonly Item[]) => Result;
}
let { items, computeExpensive }: Props = $props();
const result = $derived.by(() => computeExpensive(items));
</script>
Virtual Scrolling for Large Lists
<script lang="ts">
import { tick } from 'svelte';
interface Props {
items: readonly Item[];
itemHeight: number;
containerHeight: number;
}
let { items, itemHeight, containerHeight }: Props = $props();
let scrollTop = $state(0);
const visibleStart = $derived(Math.floor(scrollTop / itemHeight));
const visibleEnd = $derived(Math.min(
visibleStart + Math.ceil(containerHeight / itemHeight) + 1,
items.length
));
const visibleItems = $derived(items.slice(visibleStart, visibleEnd));
const offsetY = $derived(visibleStart * itemHeight);
</script>
<div
style="height: {containerHeight}px; overflow-y: auto;"
onscroll={(e) => scrollTop = e.currentTarget.scrollTop}
>
<div style="height: {items.length * itemHeight}px; position: relative;">
<div style="transform: translateY({offsetY}px);">
{#each visibleItems as item}
<slot {item} />
{/each}
Code Quality Standards
Naming Conventions
- Components: PascalCase (
UserProfile.svelte, DataTable.svelte)
- Stores: camelCase with descriptive names (
userSession, shoppingCart)
- Actions: camelCase verbs (
clickOutside, trapFocus)
- Types/Interfaces: PascalCase (
UserData, ApiResponse)
- Constants: SCREAMING_SNAKE_CASE (
API_BASE_URL, MAX_RETRIES)
Documentation
- Component props: Always include JSDoc for non-obvious props
- Store methods: Document side effects and return types
- Complex logic: Add inline comments explaining the "why", not the "what"
- Public APIs: Full JSDoc with examples
Testing Strategy
- Unit tests: Test stores and utility functions in isolation
- Component tests: Test component behavior with Vitest + Testing Library
- Integration tests: Test user workflows with Playwright
- Type tests: Use
expectType from tsd for complex type utilities
Anti-Patterns to Avoid
❌ Don't
let { items }: Props = $props();
items.push(newItem);
$: filteredItems = items.filter(i => {
});
<script>
</script>
function processData(data: any) {}
✅ Do
let { items }: Props = $props();
const updatedItems = [...items, newItem];
const filteredItems = $derived(filterItems(items, filters));
function processData(data: UserData): ProcessedData {}
Advanced Patterns
Context API for Dependency Injection
import { setContext, getContext } from 'svelte';
import { writable, type Writable } from 'svelte/store';
const THEME_KEY = Symbol('theme');
export interface ThemeContext {
theme: Writable<'light' | 'dark'>;
toggle: () => void;
}
export function setThemeContext(): ThemeContext {
const theme = writable<'light' | 'dark'>('light');
const context: ThemeContext = {
theme,
toggle: () => theme.update((t) => (t === 'light' ? 'dark' : 'light'))
};
setContext(THEME_KEY, context);
return context;
}
export function getThemeContext(): ThemeContext {
const context = getContext<>();
(!context) {
();
}
context;
}
Form Validation Pattern
import { writable, derived, type Readable } from 'svelte/store';
type ValidationRule<T> = (value: T) => string | null;
interface FieldState<T> {
value: T;
error: string | null;
touched: boolean;
}
export function createFormField<T>(initialValue: T, validators: readonly ValidationRule<T>[] = []) {
const state = writable<FieldState<T>>({
value: initialValue,
error: null,
touched: false
});
const { subscribe, update } = state;
function validate(value: T): string | null {
for (const validator of validators) {
const error = validator(value);
if (error) return error;
}
return null;
}
return {
subscribe,
setValue:
( ({
...s,
value,
: (value)
})),
: ( ({ ...s, : })),
:
( ({
: initialValue,
: ,
:
}))
};
}
Decision Framework
When to create a new component?
- Reusability: Will this be used in 2+ places?
- Complexity: Is the logic complex enough to warrant isolation?
- Single Responsibility: Does it do one clear thing?
- If yes to any → Create component
When to use a store?
- Shared state: Needed across multiple components?
- Complex logic: State updates involve business logic?
- Persistence: Needs to survive component unmounts?
- If yes to any → Use store
When to use context vs props?
- Depth: Passing through 3+ levels? → Context
- Scope: Only parent-child? → Props
- Type: Configuration/theme data? → Context
- Type: Component-specific data? → Props
Output Expectations
When writing Svelte code, always:
- Start with types: Define interfaces before implementation
- Plan component API: Think about props, events, and slots first
- Extract early: Don't wait for duplication—extract when you see potential reuse
- Test boundaries: Write tests for public APIs and edge cases
- Document decisions: Comment non-obvious architectural choices
- Review imports: Ensure clean dependency graph, avoid circular dependencies
- Storybook: Create stories for all core library components to verify states and documentation
File Templates
Component Template
<script lang="ts">
/**
* [Component description]
*
* @example
* ```svelte
* <ComponentName prop1="value" on:event={handler} />
* ```
*/
import type { ComponentType } from 'svelte';
interface Props {
// Define all props with types
}
let {
// Destructure with defaults
}: Props = $props();
// Derived state
// Event handlers
// Lifecycle (if needed)
</script>
<!-- Template -->
<style>
/* Scoped styles */
</style>
Store Template
import { writable, type Readable } from 'svelte/store';
interface State {
}
interface Store extends Readable<State> {
}
function createStore(initialState: State): Store {
const { subscribe, update, set } = writable<State>(initialState);
return {
subscribe
};
}
export const myStore = createStore({
});
Storybook Story Template
import type { Meta, StoryObj } from '@storybook/svelte';
import ComponentName from './ComponentName.svelte';
const meta = {
title: 'Domain/ComponentName',
component: ComponentName,
tags: ['autodocs'],
argTypes: {
variant: {
control: { type: 'select' },
options: ['primary', 'secondary']
},
disabled: { control: 'boolean' }
}
} satisfies Meta<ComponentName>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
label: 'Button',
disabled: false
}
};
export const WithVariant: Story = {
args: {
: ,
:
}
};
Critical Reminders
- Immutability: Always create new objects/arrays for store updates
- Type exports: Export types/interfaces from modules for consumer use
- Error boundaries: Handle errors gracefully with try-catch and error states
- Accessibility: Include ARIA attributes, keyboard navigation, and semantic HTML
- Performance: Profile before optimizing—measure, don't assume
- Bundle size: Import only what you need (
import { specific } from 'module')
- Backwards compatibility: When updating stores/components, maintain API compatibility
Integration with Other Tools
SvelteKit Integration
- Use
$app/stores for navigation state
- Leverage
load functions for data fetching
- Type
PageData and LayoutData explicitly
- Use
invalidate and invalidateAll for cache management
Tailwind CSS Integration
- Use
@apply sparingly—prefer utility classes
- Extract common patterns to components, not CSS
- Use Tailwind's
theme() function for consistency
Vitest Integration
- Mock stores using
vi.mock()
- Test reactive statements with
tick()
- Use
render from @testing-library/svelte
Storybook Integration
- Mandatory for Core: All core library components must have accompanying stories
- Visual Testing: Use stories to verify all component states (loading, error, empty)
- Documentation: Leverage
autodocs for auto-generated documentation
- Interaction: Use the play function for interaction tests within Storybook
Example: Complete Feature Module
Here's how all patterns come together:
lib/features/todo/
├── components/
│ ├── TodoList.svelte # Container component
│ ├── TodoItem.svelte # Presentational component
│ └── TodoForm.svelte # Form component
├── stores/
│ └── todos.ts # Custom store with methods
├── types/
│ └── index.ts # Type definitions
├── actions/
│ └── auto-focus.ts # Reusable action
└── index.ts # Public API barrel export
This structure ensures:
- ✅ Clear separation of concerns
- ✅ Easy to test in isolation
- ✅ Reusable across projects
- ✅ Type-safe throughout
- ✅ Scalable and maintainable
Remember: The best code is code that doesn't need comments because it's self-documenting through clear types, meaningful names, and obvious structure. Write code that your future self will thank you for.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.