---
trigger: glob
glob: *.svelte
---

| No | Category   | Guideline                        | Description                                      | Do                                                                 | Don't                                                        | Code Good                                                                 | Code Bad                                                                 | Severity   | Docs URL                                                                 |
|----|------------|----------------------------------|--------------------------------------------------|--------------------------------------------------------------------|--------------------------------------------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------|------------|-------------------------------------------------------------------------|
| 1  | Reactivity | Use $: for reactive statements   | Automatic dependency tracking                    | $: for derived values                                              | Manual recalculation                                          | $: doubled = count * 2                                                   | let doubled; count && (doubled = count * 2)                              | Medium     | [Svelte Docs](https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive) |
| 2  | Reactivity | Trigger reactivity with assignment | Svelte tracks assignments not mutations          | Reassign arrays/objects to trigger update                          | Mutate without reassignment                                  | items = [...items, newItem]                                              | items.push(newItem)                                                      | High       | [Svelte Docs](https://svelte.dev/docs/svelte-components#script-2-assignments-are-reactive) |
| 3  | Reactivity | Use $state in Svelte 5           | Runes for explicit reactivity                    | let count = $state(0)                                              | Implicit reactivity in Svelte 5                               | let count = $state(0)                                                    | let count = 0 (Svelte 5)                                                 | Medium     | [Svelte Blog](https://svelte.dev/blog/runes)                           |
| 4  | Reactivity | Use $derived for computed values | $derived replaces $: in Svelte 5                  | let doubled = $derived(count * 2)                                  | $: in Svelte 5                                                | let doubled = $derived(count * 2)                                        | $: doubled = count * 2 (Svelte 5)                                        | Medium     | -                                                                      |
| 5  | Reactivity | Use $effect for side effects     | $effect replaces $: side effects                  | Use $effect for subscriptions                                      | $: for side effects in Svelte 5                               | $effect(() => console.log(count))                                       | $: console.log(count) (Svelte 5)                                         | Medium     | -                                                                      |
| 6  | Props      | Export let for props             | Declare props with export let                    | export let propName                                                | Props without export                                         | export let count = 0                                                     | let count = 0                                                            | High       | [Svelte Docs](https://svelte.dev/docs/svelte-components#script-1-export-creates-a-component-prop) |
| 7  | Props      | Use $props in Svelte 5           | $props rune for prop access                       | let { name } = $props()                                            | export let in Svelte 5                                        | let { name, age = 0 } = $props()                                         | export let name; export let age = 0                                      | Medium     | -                                                                      |
| 8  | Props      | Provide default values           | Default props with assignment                     | export let count = 0                                               | Required props without defaults                               | export let count = 0                                                     | export let count                                                         | Low        | -                                                                      |
| 9  | Props      | Use spread props                 | Pass through unknown props                        | {...$$restProps} on elements                                       | Manual prop forwarding                                        | <button {...$$restProps}>                                                | <button class={$$props.class}>                                            | Low        | [Svelte Docs](https://svelte.dev/docs/basic-markup#attributes-and-props) |
| 10 | Bindings   | Use bind: for two-way binding    | Simplified input handling                         | bind:value for inputs                                              | on:input with manual update                                   | <input bind:value={name}>                                                | <input value={name} on:input={e => name = e.target.value}>                | Low        | [Svelte Docs](https://svelte.dev/docs/element-directives#bind-property)  |
| 11 | Bindings   | Bind to DOM elements             | Reference DOM nodes                               | bind:this for element reference                                    | querySelector in onMount                                      | <div bind:this={el}>                                                     | onMount(() => el = document.querySelector())                             | Medium     | -                                                                      |
| 12 | Bindings   | Use bind:group for radios/checkboxes | Simplified group handling                         | bind:group for radio/checkbox groups                               | Manual checked handling                                       | <input type="radio" bind:group={selected}>                               | <input type="radio" checked={selected === value}>                        | Low        | -                                                                      |
| 13 | Events     | Use on: for event handlers       | Event directive syntax                           | on:click={handler}                                                 | addEventListener in onMount                                    | <button on:click={handleClick}>                                          | onMount(() => btn.addEventListener())                                    | Medium     | [Svelte Docs](https://svelte.dev/docs/element-directives#on-eventname)   |
| 14 | Events     | Forward events with on:event     | Pass events to parent                             | on:click without handler                                           | createEventDispatcher for DOM events                          | <button on:click>                                                        | dispatch('click', event)                                                 | Low        | -                                                                      |
| 15 | Events     | Use createEventDispatcher        | Custom component events                           | dispatch for custom events                                         | on:event for custom events                                    | dispatch('save', { data })                                               | on:save without dispatch                                                 | Medium     | [Svelte Docs](https://svelte.dev/docs/svelte#createeventdispatcher)     |
| 16 | Lifecycle  | Use onMount for initialization   | Run code after component mounts                  | onMount for setup and data fetching                                 | Code in script body for side effects                          | onMount(() => fetchData())                                               | fetchData() in script body                                               | High       | [Svelte Docs](https://svelte.dev/docs/svelte#onmount)                   |
| 17 | Lifecycle  | Return cleanup from onMount      | Automatic cleanup on destroy                      | Return function from onMount                                       | Separate onDestroy for paired cleanup                         | onMount(() => { sub(); return unsub })                                    | onMount(sub); onDestroy(unsub)                                           | Medium     | -                                                                      |
| 18 | Lifecycle  | Use onDestroy sparingly          | Only when onMount cleanup not possible           | onDestroy for non-mount cleanup                                    | onDestroy for mount-related cleanup                           | onDestroy for store unsubscribe                                          | onDestroy(() => clearInterval(id))                                       | Low        | -                                                                      |
| 19 | Lifecycle  | Avoid beforeUpdate/afterUpdate   | Usually not needed                               | Reactive statements instead                                       | beforeUpdate for derived state                                | $: if (x) doSomething()                                                  | beforeUpdate(() => doSomething())                                        | Low        | -                                                                      |
| 20 | Stores     | Use writable for mutable state   | Basic reactive store                              | writable for shared mutable state                                  | Local variables for shared state                              | const count = writable(0)                                                | let count = 0 in module                                                  | Medium     | [Svelte Docs](https://svelte.dev/docs/svelte-store#writable)           |
| 21 | Stores     | Use readable for read-only state | External data sources                             | readable for derived/external data                                 | writable for read-only data                                   | readable(0, set => interval(set))                                        | writable(0) for timer                                                    | Low        | [Svelte Docs](https://svelte.dev/docs/svelte-store#readable)           |
| 22 | Stores     | Use derived for computed stores  | Combine or transform stores                       | derived for computed values                                       | Manual subscription for derived                               | derived(count, $c => $c * 2)                                             | count.subscribe(c => doubled = c * 2)                                    | Medium     | [Svelte Docs](https://svelte.dev/docs/svelte-store#derived)            |
| 23 | Stores     | Use $ prefix for auto-subscription | Automatic subscribe/unsubscribe                   | $storeName in components                                           | Manual subscription                                           | {$count}                                                                | count.subscribe(c => value = c)                                          | High       | -                                                                      |
| 24 | Stores     | Clean up custom subscriptions    | Unsubscribe when component destroys               | Return unsubscribe from onMount                                    | Leave subscriptions open                                      | onMount(() => store.subscribe(fn))                                       | store.subscribe(fn) in script                                            | High       | -                                                                      |
| 25 | Slots      | Use slots for composition        | Content projection                               | <slot> for flexible content                                       | Props for all content                                         | <slot>Default</slot>                                                     | <Component content="text"/>                                              | Medium     | [Svelte Docs](https://svelte.dev/docs/special-elements#slot)           |
| 26 | Slots      | Name slots for multiple areas    | Multiple content areas                           | <slot name="header">                                              | Single slot for complex layouts                               | <slot name="header"><slot name="footer">                                  | <slot> with complex conditionals                                         | Low        | -                                                                      |
| 27 | Slots      | Check slot content with $$slots  | Conditional slot rendering                        | $$slots.name for conditional rendering                            | Always render slot wrapper                                    | {#if $$slots.footer}<slot name="footer"/>{/if}                            | <div><slot name="footer"/></div>                                         | Low        | -                                                                      |
| 28 | Styling    | Use scoped styles by default     | Styles scoped to component                       | <style> for component styles                                       | Global styles for component                                   | :global() only when needed                                               | <style> all global                                                      | Medium     | [Svelte Docs](https://svelte.dev/docs/svelte-components#style)         |
| 29 | Styling    | Use :global() sparingly          | Escape scoping when needed                        | :global for third-party styling                                    | Global for all styles                                         | :global(.external-lib)                                                   | <style> without scoping                                                  | Medium     | -                                                                      |
| 30 | Styling    | Use CSS variables for theming    | Dynamic styling                                   | CSS custom properties                                              | Inline styles for themes                                      | style="--color: {color}"                                                 | style="color: {color}"                                                   | Low        | -                                                                      |
| 31 | Transitions| Use built-in transitions         | Svelte transition directives                      | transition:fade for simple effects                                 | Manual CSS transitions                                        | <div transition:fade>                                                    | <div class:fade={visible}>                                               | Low        | [Svelte Docs](https://svelte.dev/docs/element-directives#transition-fn) |
| 32 | Transitions| Use in: and out: separately      | Different enter/exit animations                   | in:fly out:fade for asymmetric                                     | Same transition for both                                      | <div in:fly out:fade>                                                    | <div transition:fly>                                                     | Low        | -                                                                      |
| 33 | Transitions| Add local modifier               | Prevent ancestor trigger                          | transition:fade|local                                             | Global transitions for lists                                  | <div transition:slide|local>                                             | <div transition:slide>                                                   | Medium     | -                                                                      |
| 34 | Actions    | Use actions for DOM behavior     | Reusable DOM logic                               | use:action for DOM enhancements                                    | onMount for each usage                                        | <div use:clickOutside>                                                   | onMount(() => setupClickOutside(el))                                      | Medium     | [Svelte Docs](https://svelte.dev/docs/element-directives#use-action)    |
| 35 | Actions    | Return update and destroy        | Lifecycle methods for actions                     | Return { update, destroy }                                         | Only initial setup                                            | return { update(params) {}, destroy() {} }                                | return destroy only                                                      | Medium     | -                                                                      |
| 36 | Actions    | Pass parameters to actions       | Configure action behavior                         | use:action={params}                                                | Hardcoded action behavior                                     | <div use:tooltip={options}>                                              | <div use:tooltip>                                                        | Low        | -                                                                      |
| 37 | Logic      | Use {#if} for conditionals       | Template conditionals                             | {#if} {:else if} {:else}                                           | Ternary in expressions                                        | {#if cond}...{:else}...{/if}                                             | {cond ? a : b} for complex                                                | Low        | [Svelte Docs](https://svelte.dev/docs/logic-blocks#if)                 |
| 38 | Logic      | Use {#each} for lists            | List rendering                                    | {#each} with key                                                   | Map in expression                                             | {#each items as item (item.id)}                                          | {items.map(i => `<div>${i}</div>`)}                                      | Medium     | -                                                                      |
| 39 | Logic      | Always use keys in {#each}       | Proper list reconciliation                        | (item.id) for unique key                                           | Index as key or no key                                        | {#each items as item (item.id)}                                          | {#each items as item, i (i)}                                             | High       | -                                                                      |
| 40 | Logic      | Use {#await} for promises        | Handle async states                               | {#await} for loading/error states                                  | Manual promise handling                                       | {#await promise}...{:then}...{:catch}                                    | {#if loading}...{#if error}                                              | Medium     | [Svelte Docs](https://svelte.dev/docs/logic-blocks#await)              |
| 41 | SvelteKit  | Use +page.svelte for routes      | File-based routing                                | +page.svelte for route components                                  | Custom routing setup                                          | routes/about/+page.svelte                                                | routes/About.svelte                                                      | Medium     | [SvelteKit Docs](https://kit.svelte.dev/docs/routing)                  |
| 42 | SvelteKit  | Use +page.js for data loading    | Load data before render                           | load function in +page.js                                          | onMount for data fetching                                     | export function load() {}                                                | onMount(() => fetchData())                                                | High       | [SvelteKit Docs](https://kit.svelte.dev/docs/load)                     |
| 43 | SvelteKit  | Use +page.server.js for server-only | Server-side data loading                          | +page.server.js for sensitive data                                 | +page.js for API keys                                         | +page.server.js with DB access                                           | +page.js with DB access                                                  | High       | -                                                                      |
| 44 | SvelteKit  | Use form actions                 | Server-side form handling                         | +page.server.js actions                                            | API routes for forms                                          | export const actions = { default }                                       | fetch('/api/submit')                                                     | Medium     | [SvelteKit Docs](https://kit.svelte.dev/docs/form-actions)             |
| 45 | SvelteKit  | Use $app/stores for app state    | $page $navigating $updated                        | $page for current page data                                        | Manual URL parsing                                            | import { page } from '$app/stores'                                       | window.location.pathname                                                  | Medium     | [SvelteKit Docs](https://kit.svelte.dev/docs/modules#$app-stores)       |
| 46 | Performance| Use {#key} for forced re-render | Reset component state                             | {#key id} for fresh instance                                       | Manual destroy/create                                         | {#key item.id}<Component/>{/key}                                         | on:change={() => component = null}                                       | Low        | [Svelte Docs](https://svelte.dev/docs/logic-blocks#key)                |
| 47 | Performance| Avoid unnecessary reactivity    | Not everything needs $:                                                        | $: only for side effects                                         | $: for simple assignments                                      | $: if (x) console.log(x)                                                 | $: y = x (when y = x works)                                              | Low        | -                                                                      |
| 48 | Performance| Use immutable compiler option   | Skip equality checks                              | immutable: true for large lists                                    | Default for all components                                    | <svelte:options immutable/>                                              | Default without immutable                                                | Low        | -                                                                      |
| 49 | TypeScript | Use lang="ts" in script          | TypeScript support                                | <script lang="ts">                                                | JavaScript for typed projects                                 | <script lang="ts">                                                       | <script> with JSDoc                                                      | Medium     | [Svelte Docs](https://svelte.dev/docs/typescript)                      |
| 50 | TypeScript | Type props with interface        | Explicit prop types                               | interface $$Props for types                                        | Untyped props                                                 | interface $$Props { name: string }                                       | export let name                                                          | Medium     | -                                                                      |
| 51 | TypeScript | Type events with createEventDispatcher | Type-safe events                                  | createEventDispatcher<Events>()                                    | Untyped dispatch                                              | createEventDispatcher<{ save: Data }>()                                  | createEventDispatcher()                                                  | Medium     | -                                                                      |
| 52 | Accessibility| Use semantic elements          | Proper HTML in templates                          | button nav main appropriately                                      | div for everything                                            | <button on:click>                                                        | <div on:click>                                                           | High       | -                                                                      |
| 53 | Accessibility| Add aria to dynamic content    | Accessible state changes                          | aria-live for updates                                              | Silent dynamic updates                                        | <div aria-live="polite">{message}</div>                                  | <div>{message}</div>                                                     | Medium     | -                                                                      |
