All topics
Frontend · Learning hub

Svelte notes for developers

Master Svelte with a curated set of 7 developer notes — core concepts, patterns, and interview prep. Maintained by the DevRecall team.

Save this stack to your DevRecallMore Frontend notes
Svelte

Reactivity & Stores

Svelte Reactivity & Stores Svelte is a radical new approach to building user interfaces. It compiles components into highly efficient imperative code that updat

Svelte Reactivity & Stores

Svelte is a radical new approach to building user interfaces. It compiles components into highly efficient imperative code that updates the DOM surgically. Reactivity in Svelte is built into the language itself.

Reactive Declarations

Svelte automatically tracks dependencies and updates the DOM when state changes. Use the $ label for reactive declarations.

<script>
  // Regular variable - reactive by assignment
  let count = 0;
  let name = 'Svelte';
  
  // Reactive declaration - auto-updates when dependencies change
  $: doubled = count * 2;
  $: quadrupled = doubled * 2;
  
  // Reactive statement - runs when dependencies change
  $: {
    console.log('Count changed to:', count);
    console.log('Doubled:', doubled);
  }
  
  // Conditional reactive statement
  $: if (count > 10) {
    console.log('Count is greater than 10!');
  }
  
  function increment() {
    count += 1;  // Assignment triggers reactivity
  }
  
  function reset() {
    count = 0;
  }
</script>

<h1>{name}</h1>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<p>Quadrupled: {quadrupled}</p>

<button on:click={increment}>+1</button>
<button on:click={reset}>Reset</button>

Arrays and Objects Reactivity

<script>
  let todos = [
    { id: 1, text: 'Learn Svelte', done: false },
    { id: 2, text: 'Build app', done: false }
  ];
  
  let user = {
    name: 'John',
    email: 'john@example.com',
    age: 30
  };
  
  // ✅ Triggers reactivity - reassignment
  function addTodo() {
    todos = [...todos, { id: Date.now(), text: 'New todo', done: false }];
  }
  
  // ✅ Triggers reactivity - reassignment
  function updateUser() {
    user = { ...user, age: 31 };
  }
  
  // ❌ Won't trigger reactivity - mutation
  function addTodoWrong() {
    todos.push({ id: Date.now(), text: 'New', done: false });
    // Need to reassign: todos = todos
  }
  
  // ✅ Fix: Reassign after mutation
  function addTodoCorrect() {
    todos.push({ id: Date.now(), text: 'New', done: false });
    todos = todos;  // Trigger reactivity
  }
  
  // ✅ Better: Use spread
  function toggleTodo(id) {
    todos = todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    );
  }
  
  // Array methods that need reassignment:
  // push, pop, shift, unshift, splice, sort, reverse
</script>

<ul>
  {#each todos as todo (todo.id)}
    <li>
      <input type="checkbox" checked={todo.done} on:change={() => toggleTodo(todo.id)} />
      {todo.text}
    </li>
  {/each}
</ul>

<button on:click={addTodo}>Add Todo</button>

Stores - Shared State

Svelte stores provide a way to share state across components without prop drilling.

Writable Stores

// stores.js
import { writable } from 'svelte/store';

// Create writable store with initial value
export const count = writable(0);
export const user = writable(null);
export const todos = writable([]);

// Store with custom logic
function createCounter() {
  const { subscribe, set, update } = writable(0);
  
  return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
  };
}

export const counter = createCounter();

// Component.svelte
<script>
  import { count, user, counter } from './stores';
  
  // Method 1: Subscribe manually
  let countValue;
  const unsubscribe = count.subscribe(value => {
    countValue = value;
  });
  
  // Cleanup
  import { onDestroy } from 'svelte';
  onDestroy(unsubscribe);
  
  // Method 2: Auto-subscribe with $
  // $count is automatically reactive and auto-unsubscribes
  
  function increment() {
    count.update(n => n + 1);
    // Or: count.set($count + 1);
  }
  
  function setUser() {
    user.set({ name: 'John', email: 'john@example.com' });
  }
</script>

<h1>Count: {$count}</h1>
<p>User: {$user?.name || 'None'}</p>

<button on:click={increment}>Increment</button>
<button on:click={() => counter.increment()}>Counter Increment</button>
<button on:click={setUser}>Set User</button>

Readable Stores

import { readable } from 'svelte/store';

// Readable store - cannot be set from outside
export const time = readable(new Date(), set => {
  const interval = setInterval(() => {
    set(new Date());
  }, 1000);
  
  // Cleanup function (called when last subscriber unsubscribes)
  return () => clearInterval(interval);
});

// Mouse position store
export const mouse = readable({ x: 0, y: 0 }, set => {
  const handleMove = (event) => {
    set({ x: event.clientX, y: event.clientY });
  };
  
  document.addEventListener('mousemove', handleMove);
  
  return () => {
    document.removeEventListener('mousemove', handleMove);
  };
});

// Usage
<script>
  import { time, mouse } from './stores';
</script>

<p>Time: {$time.toLocaleTimeString()}</p>
<p>Mouse: {$mouse.x}, {$mouse.y}</p>

Derived Stores

import { derived, writable } from 'svelte/store';

export const todos = writable([
  { id: 1, text: 'Todo 1', done: false },
  { id: 2, text: 'Todo 2', done: true },
  { id: 3, text: 'Todo 3', done: false }
]);

// Derived from single store
export const completedTodos = derived(
  todos,
  $todos => $todos.filter(t => t.done)
);

export const activeTodos = derived(
  todos,
  $todos => $todos.filter(t => !t.done)
);

export const todoStats = derived(
  todos,
  $todos => ({
    total: $todos.length,
    completed: $todos.filter(t => t.done).length,
    active: $todos.filter(t => !t.done).length
  })
);

// Derived from multiple stores
const firstName = writable('John');
const lastName = writable('Doe');

export const fullName = derived(
  [firstName, lastName],
  ([$firstName, $lastName]) => `${$firstName} ${$lastName}`
);

// Usage
<script>
  import { completedTodos, activeTodos, todoStats } from './stores';
</script>

<p>Total: {$todoStats.total}</p>
<p>Completed: {$todoStats.completed}</p>
<p>Active: {$todoStats.active}</p>

<h3>Completed Todos:</h3>
{#each $completedTodos as todo}
  <p>{todo.text}</p>
{/each}

Custom Stores

// stores/auth.js
import { writable } from 'svelte/store';

function createAuthStore() {
  const { subscribe, set, update } = writable({
    user: null,
    token: null,
    isAuthenticated: false
  });
  
  return {
    subscribe,
    login: async (credentials) => {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials)
      });
      const data = await response.json();
      set({
        user: data.user,
        token: data.token,
        isAuthenticated: true
      });
    },
    logout: () => {
      set({
        user: null,
        token: null,
        isAuthenticated: false
      });
    },
    updateUser: (userData) => {
      update(state => ({
        ...state,
        user: { ...state.user, ...userData }
      }));
    }
  };
}

export const auth = createAuthStore();

// Usage
<script>
  import { auth } from './stores/auth';
  
  async function handleLogin() {
    await auth.login({ email, password });
  }
</script>

{#if $auth.isAuthenticated}
  <p>Welcome, {$auth.user.name}!</p>
  <button on:click={() => auth.logout()}>Logout</button>
{:else}
  <button on:click={handleLogin}>Login</button>
{/if}
Svelte

Component Communication

Svelte Component Communication Learn how Svelte components communicate through props, events, slots, and context: Props - Parent to Child <!-- Child.svelte -->

Svelte Component Communication

Learn how Svelte components communicate through props, events, slots, and context:

Props - Parent to Child

<!-- Child.svelte -->
<script>
  // Declare props with export
  export let title;
  export let count = 0;  // With default value
  export let user = null;  // Optional prop
  
  // Props are reactive
  $: console.log('Title changed:', title);
</script>

<div>
  <h2>{title}</h2>
  <p>Count: {count}</p>
  {#if user}
    <p>User: {user.name}</p>
  {/if}
</div>

<!-- Parent.svelte -->
<script>
  import Child from './Child.svelte';
  
  let parentTitle = 'Hello';
  let parentCount = 5;
  let currentUser = { name: 'John' };
</script>

<Child title={parentTitle} count={parentCount} user={currentUser} />

<!-- Shorthand when variable name matches prop name -->
<Child {title} {count} {user} />

Events - Child to Parent

<!-- Child.svelte -->
<script>
  import { createEventDispatcher } from 'svelte';
  
  const dispatch = createEventDispatcher();
  
  function sendMessage() {
    dispatch('message', {
      text: 'Hello from child'
    });
  }
  
  function increment() {
    dispatch('increment', { value: 1 });
  }
</script>

<button on:click={sendMessage}>Send Message</button>
<button on:click={increment}>Increment</button>

<!-- Parent.svelte -->
<script>
  import Child from './Child.svelte';
  
  let count = 0;
  let lastMessage = '';
  
  function handleMessage(event) {
    lastMessage = event.detail.text;
  }
  
  function handleIncrement(event) {
    count += event.detail.value;
  }
</script>

<Child on:message={handleMessage} on:increment={handleIncrement} />

<p>Count: {count}</p>
<p>Last message: {lastMessage}</p>

Two-Way Binding (bind:)

<!-- Child.svelte -->
<script>
  export let value;
</script>

<input type="text" bind:value />

<!-- Parent.svelte -->
<script>
  import Child from './Child.svelte';
  let searchQuery = '';
</script>

<!-- Two-way binding -->
<Child bind:value={searchQuery} />
<p>You typed: {searchQuery}</p>

Slots - Content Projection

<!-- Card.svelte -->
<div class="card">
  <header>
    <slot name="header">Default Header</slot>
  </header>
  
  <main>
    <slot>Default content</slot>
  </main>
  
  <footer>
    <slot name="footer" />
  </footer>
</div>

<!-- Usage -->
<script>
  import Card from './Card.svelte';
</script>

<Card>
  <h2 slot="header">Card Title</h2>
  
  <!-- Default slot -->
  <p>This is the main content.</p>
  
  <div slot="footer">
    <button>Cancel</button>
    <button>Save</button>
  </div>
</Card>

<!-- Slot props - pass data to parent -->
<!-- List.svelte -->
<script>
  export let items = [];
</script>

{#each items as item, index}
  <slot {item} {index}>
    <!-- Fallback content -->
    <p>{item.name}</p>
  </slot>
{/each}

<!-- Parent usage -->
<List {items} let:item let:index>
  <div>
    <strong>{index + 1}.</strong>
    <span>{item.name}</span>
    <span>${item.price}</span>
  </div>
</List>

Context API

<!-- Parent.svelte -->
<script>
  import { setContext } from 'svelte';
  import Child from './Child.svelte';
  
  const theme = {
    color: 'blue',
    background: 'white'
  };
  
  setContext('theme', theme);
  
  // Can also use writable store
  import { writable } from 'svelte/store';
  const user = writable({ name: 'John' });
  setContext('user', user);
</script>

<Child />

<!-- Child.svelte (any level deep) -->
<script>
  import { getContext } from 'svelte';
  
  const theme = getContext('theme');
  const user = getContext('user');
</script>

<div style="color: {theme.color}; background: {theme.background}">
  <p>User: {$user.name}</p>
</div>
Svelte

SvelteKit & Routing

SvelteKit & Routing SvelteKit is the official application framework for Svelte. It provides routing, server-side rendering, API endpoints, and a powerful filesy

SvelteKit & Routing

SvelteKit is the official application framework for Svelte. It provides routing, server-side rendering, API endpoints, and a powerful filesystem-based routing system.

Filesystem-Based Routing

// Project structure defines routes
src/routes/
  +page.svelte              → /
  about/+page.svelte        → /about
  blog/+page.svelte         → /blog
  blog/[slug]/+page.svelte  → /blog/:slug
  users/[id]/+page.svelte   → /users/:id
  admin/
    +layout.svelte          → Layout for /admin/*
    +page.svelte            → /admin
    users/+page.svelte      → /admin/users

// src/routes/+page.svelte (home page)
<script>
  export let data;  // From load function
</script>

<h1>Welcome to SvelteKit</h1>
<p>{data.message}</p>

// src/routes/blog/[slug]/+page.svelte
<script>
  export let data;
</script>

<article>
  <h1>{data.post.title}</h1>
  <div>{@html data.post.content}</div>
</article>

Loading Data

// src/routes/+page.ts (or +page.server.ts)
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params, url, fetch }) => {
  return {
    message: 'Hello from load function'
  };
};

// src/routes/blog/[slug]/+page.ts
export const load: PageLoad = async ({ params, fetch }) => {
  const response = await fetch(`/api/posts/${params.slug}`);
  const post = await response.json();
  
  return {
    post
  };
};

// Server-only load function (+page.server.ts)
import type { PageServerLoad } from './$types';
import { db } from '$lib/server/database';

export const load: PageServerLoad = async ({ params }) => {
  // Can access database, environment variables, etc.
  const post = await db.posts.findOne({ slug: params.slug });
  
  return {
    post
  };
};

Layouts

// src/routes/+layout.svelte (root layout)
<script>
  export let data;
</script>

<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a href="/blog">Blog</a>
</nav>

<main>
  <slot />  <!-- Child pages render here -->
</main>

<footer>
  <p>© 2024 My App</p>
</footer>

// src/routes/blog/+layout.svelte (nested layout)
<script>
  export let data;
</script>

<div class="blog-layout">
  <aside>
    <h3>Categories</h3>
    {#each data.categories as category}
      <a href="/blog/category/{category.slug}">{category.name}</a>
    {/each}
  </aside>
  
  <div class="content">
    <slot />  <!-- Blog pages render here -->
  </div>
</div>

Navigation

<script>
  import { goto, invalidate, invalidateAll } from '$app/navigation';
  import { page } from '$app/stores';
  
  // Current page data
  $: console.log('Current path:', $page.url.pathname);
  $: console.log('Params:', $page.params);
  $: console.log('Search params:', $page.url.searchParams);
  
  function navigateToPost(slug) {
    goto(`/blog/${slug}`);
  }
  
  function navigateWithOptions() {
    goto('/about', {
      replaceState: true,  // Replace history instead of push
      noScroll: true,      // Don't scroll to top
      keepFocus: true      // Keep focus on current element
    });
  }
  
  // Invalidate data
  function refresh() {
    invalidateAll();  // Rerun all load functions
  }
</script>

<!-- Declarative navigation -->
<a href="/about">About</a>
<a href="/blog/{post.slug}">Read More</a>

Form Actions

// src/routes/login/+page.server.ts
import type { Actions } from './$types';
import { fail, redirect } from '@sveltejs/kit';

export const actions: Actions = {
  login: async ({ request, cookies }) => {
    const data = await request.formData();
    const email = data.get('email');
    const password = data.get('password');
    
    // Validate
    if (!email || !password) {
      return fail(400, { email, missing: true });
    }
    
    // Authenticate
    const user = await authenticateUser(email, password);
    
    if (!user) {
      return fail(401, { email, incorrect: true });
    }
    
    // Set cookie
    cookies.set('session', user.sessionId, {
      path: '/',
      httpOnly: true,
      sameSite: 'strict',
      maxAge: 60 * 60 * 24 * 7  // 1 week
    });
    
    throw redirect(303, '/dashboard');
  }
};

// src/routes/login/+page.svelte
<script>
  import { enhance } from '$app/forms';
  export let form;  // Action response
</script>

<form method="POST" action="?/login" use:enhance>
  <input name="email" type="email" value={form?.email ?? ''} />
  {#if form?.missing}
    <p class="error">Email and password required</p>
  {/if}
  {#if form?.incorrect}
    <p class="error">Invalid credentials</p>
  {/if}
  
  <input name="password" type="password" />
  <button>Login</button>
</form>
Svelte

Transitions & Animations

Svelte Transitions & Animations Svelte makes it easy to add smooth transitions and animations to your app with built-in transition directives. Built-in Transiti

Svelte Transitions & Animations

Svelte makes it easy to add smooth transitions and animations to your app with built-in transition directives.

Built-in Transitions

<script>
  import { fade, fly, slide, scale, blur, draw } from 'svelte/transition';
  import { quintOut } from 'svelte/easing';
  
  let visible = true;
</script>

<!-- Fade -->
{#if visible}
  <p transition:fade>Fades in and out</p>
{/if}

<!-- Fly -->
{#if visible}
  <p transition:fly="{{ y: 200, duration: 500 }}">Flies in from below</p>
{/if}

<!-- Slide -->
{#if visible}
  <p transition:slide>Slides in and out</p>
{/if}

<!-- Scale -->
{#if visible}
  <p transition:scale="{{ start: 0, duration: 500, easing: quintOut }}">
    Scales in and out
  </p>
{/if}

<!-- Separate in and out transitions -->
{#if visible}
  <p in:fly="{{ y: 200 }}" out:fade>Different transitions</p>
{/if}

<!-- Local transitions (don't play on initial render) -->
{#if visible}
  <p transition:fade|local>Only when toggled, not on mount</p>
{/if}

<button on:click={() => visible = !visible}>Toggle</button>

Custom Transitions

<script>
  function customTransition(node, { duration = 400 }) {
    return {
      duration,
      css: t => {
        const eased = quintOut(t);
        return `
          opacity: ${eased};
          transform: scale(${eased}) rotate(${eased * 360}deg);
        `;
      }
    };
  }
  
  // JavaScript-based transition
  function typewriter(node, { speed = 50 }) {
    const text = node.textContent;
    const duration = text.length * speed;
    
    return {
      duration,
      tick: t => {
        const i = Math.trunc(text.length * t);
        node.textContent = text.slice(0, i);
      }
    };
  }
</script>

{#if visible}
  <p transition:customTransition>Custom transition</p>
  <p in:typewriter="{{ speed: 30 }}">Typing effect...</p>
{/if}

Animations

<script>
  import { flip } from 'svelte/animate';
  import { quintOut } from 'svelte/easing';
  
  let todos = [
    { id: 1, text: 'Todo 1', done: false },
    { id: 2, text: 'Todo 2', done: false }
  ];
  
  function remove(id) {
    todos = todos.filter(t => t.id !== id);
  }
</script>

<!-- Animate list reordering -->
{#each todos as todo (todo.id)}
  <div animate:flip="{{ duration: 300, easing: quintOut }}">
    {todo.text}
    <button on:click={() => remove(todo.id)}>×</button>
  </div>
{/each}

Motion (Tweened & Spring)

<script>
  import { tweened } from 'svelte/motion';
  import { spring } from 'svelte/motion';
  import { cubicOut } from 'svelte/easing';
  
  // Tweened - smooth interpolation
  const progress = tweened(0, {
    duration: 400,
    easing: cubicOut
  });
  
  // Spring - physics-based motion
  const coords = spring(
    { x: 0, y: 0 },
    {
      stiffness: 0.1,
      damping: 0.25
    }
  );
  
  function setProgress(value) {
    progress.set(value);
  }
</script>

<progress value={$progress} max="100"></progress>
<button on:click={() => setProgress(100)}>Complete</button>

<!-- Follow mouse with spring -->
<svg on:mousemove={(e) => coords.set({ x: e.clientX, y: e.clientY })}>
  <circle cx={$coords.x} cy={$coords.y} r="10" />
</svg>
Svelte

Advanced Features

Svelte Advanced Features Explore advanced Svelte features including lifecycle, actions, special elements, and compiler optimizations: Lifecycle Functions <scrip

Svelte Advanced Features

Explore advanced Svelte features including lifecycle, actions, special elements, and compiler optimizations:

Lifecycle Functions

<script>
  import { onMount, onDestroy, beforeUpdate, afterUpdate, tick } from 'svelte';
  
  let data;
  
  // Runs after component first renders
  onMount(async () => {
    console.log('Component mounted');
    
    const response = await fetch('/api/data');
    data = await response.json();
    
    // Return cleanup function
    return () => {
      console.log('Cleanup on unmount');
    };
  });
  
  // Runs just before DOM updates
  beforeUpdate(() => {
    console.log('About to update DOM');
  });
  
  // Runs after DOM updates
  afterUpdate(() => {
    console.log('DOM updated');
  });
  
  // Runs when component is destroyed
  onDestroy(() => {
    console.log('Component destroyed');
    // Cleanup subscriptions, timers, etc.
  });
  
  // Wait for pending state changes
  async function updateAndFocus() {
    count += 1;
    await tick();  // Wait for DOM update
    inputElement.focus();
  }
</script>

Actions

Actions are functions that are called when an element is created. They can be used to add custom behavior to elements.

<script>
  // Click outside action
  function clickOutside(node) {
    const handleClick = (event) => {
      if (!node.contains(event.target)) {
        node.dispatchEvent(new CustomEvent('outclick'));
      }
    };
    
    document.addEventListener('click', handleClick, true);
    
    return {
      destroy() {
        document.removeEventListener('click', handleClick, true);
      }
    };
  }
  
  // Tooltip action with parameters
  function tooltip(node, text) {
    let tooltipElement;
    
    function mouseenter() {
      tooltipElement = document.createElement('div');
      tooltipElement.textContent = text;
      tooltipElement.className = 'tooltip';
      document.body.appendChild(tooltipElement);
      
      const rect = node.getBoundingClientRect();
      tooltipElement.style.top = `${rect.bottom + 5}px`;
      tooltipElement.style.left = `${rect.left}px`;
    }
    
    function mouseleave() {
      if (tooltipElement) {
        tooltipElement.remove();
        tooltipElement = null;
      }
    }
    
    node.addEventListener('mouseenter', mouseenter);
    node.addEventListener('mouseleave', mouseleave);
    
    return {
      update(newText) {
        text = newText;
      },
      destroy() {
        node.removeEventListener('mouseenter', mouseenter);
        node.removeEventListener('mouseleave', mouseleave);
        if (tooltipElement) tooltipElement.remove();
      }
    };
  }
  
  let isOpen = false;
  let tooltipText = 'Hover over me';
</script>

<div use:clickOutside on:outclick={() => isOpen = false}>
  <button on:click={() => isOpen = true}>Open Menu</button>
  {#if isOpen}
    <div class="menu">Menu content</div>
  {/if}
</div>

<p use:tooltip={tooltipText}>Hover for tooltip</p>

Special Elements

<script>
  import Component from './Component.svelte';
  
  let currentComponent = Component;
  let components = [ComponentA, ComponentB, ComponentC];
  let selectedIndex = 0;
</script>

<!-- svelte:component - dynamic component -->
<svelte:component this={currentComponent} prop="value" />
<svelte:component this={components[selectedIndex]} />

<!-- svelte:self - recursive component -->
<script>
  export let items = [];
</script>

{#each items as item}
  <div>{item.name}</div>
  {#if item.children}
    <svelte:self items={item.children} />
  {/if}
{/each}

<!-- svelte:window - window events -->
<svelte:window
  on:keydown={(e) => console.log(e.key)}
  on:resize={(e) => console.log('Resized')}
  bind:scrollY={y}
  bind:innerWidth={width}
/>

<!-- svelte:body - body events -->
<svelte:body on:mouseenter={handleMouseEnter} />

<!-- svelte:head - modify document head -->
<svelte:head>
  <title>Page Title</title>
  <meta name="description" content="Page description" />
</svelte:head>

<!-- svelte:options - compiler options -->
<svelte:options immutable={true} />
<svelte:options accessors={true} />
Svelte

Interview Questions

Svelte Interview Questions Comprehensive Svelte interview questions covering reactivity, components, SvelteKit, and performance: Fundamentals 1. What is Svelte

Svelte Interview Questions

Comprehensive Svelte interview questions covering reactivity, components, SvelteKit, and performance:

Fundamentals

1. What is Svelte and how is it different from other frameworks?

Svelte is a compiler, not a runtime framework. It compiles components to highly efficient imperative code at build time, resulting in smaller bundles and better performance. Unlike React/Vue which ship framework code to the browser, Svelte compiles away.

2. How does reactivity work in Svelte?

Reactivity is triggered by assignments (=). When you assign a value to a variable, Svelte automatically updates the DOM. Use $: for reactive declarations that depend on other values.

3. What is the $ label?

$: creates reactive declarations and statements. Any code after $: will re-run when its dependencies change. Also used to auto-subscribe to stores with $storeName.

4. What are Svelte stores?

Stores provide a way to share state across components. Types: writable (can be set from outside), readable (read-only from outside), and derived (computed from other stores).

Components

5. How do you pass data to child components?

Use props with export let. In parent, pass data with prop={value} syntax.

6. How do components communicate with parents?

Use createEventDispatcher() to dispatch custom events. Parent listens with on:eventName.

7. What is two-way binding in Svelte?

Use bind: directive for form inputs (bind:value) or bind:prop for component props. Parent can use bind:prop={variable} for two-way binding with child.

SvelteKit

8. What is SvelteKit?

SvelteKit is the official application framework for Svelte. It provides routing, server-side rendering, API endpoints, and build optimization.

9. How does routing work in SvelteKit?

Filesystem-based routing. Files in src/routes/ define routes: +page.svelte for pages, +layout.svelte for layouts, +server.ts for API endpoints.

10. What is the load function?

load functions (+page.ts or +page.server.ts) fetch data before rendering. Server load functions run on server, universal load functions can run on both.

Advanced

11. What are actions?

Actions are functions called when an element is created. They can add event listeners, integrate third-party libraries, and return cleanup/update methods.

12. What are transitions and animations?

Built-in transitions (fade, fly, slide, scale) applied with transition: directive. Animations (flip, crossfade) coordinate element movements. Custom transitions via CSS or JS.

13. What is tick()?

tick() returns a promise that resolves when pending state changes are applied to DOM. Useful when you need to read updated DOM values.

14. What are the Svelte lifecycle functions?

onMount (after component renders), onDestroy (before component destroyed), beforeUpdate (before DOM updates), afterUpdate (after DOM updates), tick (wait for state changes).

15. How do you optimize Svelte apps?

  • Use keyed each blocks

  • Enable immutable option for components

  • Use virtual lists for large datasets

  • Lazy load components with dynamic imports

Svelte

Performance Optimization

Svelte Performance Optimization Svelte is already highly optimized by default since it compiles components to efficient vanilla JavaScript. However, there are t

Svelte Performance Optimization

Svelte is already highly optimized by default since it compiles components to efficient vanilla JavaScript. However, there are techniques to optimize further:

Keyed Each Blocks

<script>
  let items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' }
  ];
</script>

<!-- ❌ Without key - recreates all nodes -->
{#each items as item}
  <div>{item.name}</div>
{/each}

<!-- ✅ With key - only updates changed items -->
{#each items as item (item.id)}
  <div>{item.name}</div>
{/each}

<!-- With index and key -->
{#each items as item, index (item.id)}
  <div>{index + 1}. {item.name}</div>
{/each}

Immutable Data

<svelte:options immutable={true} />

<script>
  // With immutable option, Svelte uses reference equality
  // More efficient for components with many props
  export let items;
  
  // Parent must create new reference
  // items = [...items, newItem];  ✅
  // items.push(newItem);           ❌ Won't detect change
</script>

Virtual Lists

// Use svelte-virtual-list for large lists
<script>
  import VirtualList from 'svelte-virtual-list';
  
  let items = Array.from({ length: 10000 }, (_, i) => ({
    id: i,
    name: `Item ${i}`
  }));
</script>

<VirtualList {items} let:item>
  <div class="item">
    {item.name}
  </div>
</VirtualList>

Code Splitting

<script>
  import { onMount } from 'svelte';
  
  let HeavyComponent;
  let showHeavy = false;
  
  async function loadHeavyComponent() {
    const module = await import('./HeavyComponent.svelte');
    HeavyComponent = module.default;
    showHeavy = true;
  }
</script>

<button on:click={loadHeavyComponent}>Load Heavy Component</button>

{#if showHeavy && HeavyComponent}
  <svelte:component this={HeavyComponent} />
{/if}

Keep your Svelte knowledge sharp.

Save this stack to your personal DevRecall — add your own notes, track what you're learning, and share what you know with the community.

Get started — free forever