Svelte Tutorial: Learn Reactive UI Framework from Scratch (2026)
Svelte is a radical JavaScript framework that shifts the work from the browser to the compiler. Created by Rich Harris, Svelte compiles your declarative components into highly efficient imperative code that surgically updates the DOM. Unlike React or Vue that ship a runtime, Svelte compiles away, producing tiny standalone JavaScript bundles.
Svelte’s design philosophy emphasizes writing less code, using no virtual DOM, and delivering true reactivity through the language itself. The compiler understands assignments, so you update state with count += 1 rather than calling setState — the compiler handles the rest.
Reactive Declarations and Statements
Reactive declarations mark a statement that re-runs when its dependencies change. It functions like a computed value: Svelte tracks which variables are read inside the reactive block and re-executes when any of them change. Multiple reactive lines run in dependency order automatically.
Reactive statements are perfect for derived state, logging, or triggering side effects. Unlike React’s useEffect, Svelte’s reactive statements track dependencies automatically — no dependency array needed. The compiler analyzes the template and script to build the dependency graph.
Count: {count}
Doubled: {doubled}
Name: {name}
Stores for Shared State
Svelte stores provide reactive state sharing across components. A writable store holds a value and exposes subscribe, set, and update methods. readable stores are immutable, derived stores transform other stores, and custom stores encapsulate logic. The $ prefix auto-subscribes to any store in Svelte components.
Stores are framework-agnostic — they work outside Svelte components in plain JavaScript or TypeScript files. The subscribe method follows the Observable pattern. The auto-subscription in .svelte files handles cleanup on component destroy.
// store.js
import { writable, derived, readable } from 'svelte/store';
export const count = writable(0);
export const user = writable(null);
export const todos = writable([]);
export const doubled = derived(count, $count => $count * 2);
export const time = readable(new Date(), (set) => {
const interval = setInterval(() => set(new Date()), 1000);
return () => clearInterval(interval);
});
// Custom store
function createTimer() {
const { subscribe, set, update } = writable(0);
let interval;
return {
subscribe,
start: () => {
interval = setInterval(() => update(n => n + 1), 1000);
},
stop: () => {
clearInterval(interval);
},
reset: () => set(0),
};
}
export const timer = createTimer();
// Component.svelte
Count: {$count} (doubled: {$doubled})
Remaining: {$todos.filter(t => !t.done).length}
Transitions and Animations
Svelte’s built-in transition directives create smooth animations without external libraries. The transition:fade, transition:slide, and transition:scale directives animate elements entering and leaving the DOM. Parameters control duration, delay, and easing. The in: and out: directives separate enter from exit animations.
Custom transitions use functions returning CSS or JS-based animations. Svelte’s FLIP animation repositions list items when the list order changes. Crossfade pairs elements entering and exiting with a smooth transition between positions.
{#if show}
Flies into view
{/if}
{#each items as item, i (item)}
-
{item}
{/each}
Component Composition and Slots
Svelte components use export let for external data, slot elements for content projection, and named slots for multiple insertion points. Component events use createEventDispatcher. The bind: directive creates two-way bindings. The class: and style: directives apply conditional classes and inline styles.
Svelte 5 introduces runes ($state, $derived) for a unified reactivity model across components and .svelte.js files. The use: directive activates actions. $$props and $$restProps forward unknown properties.
{title}
Default footer
This is the main content.
Custom footer
Reactive Bindings and Forms
Svelte’s bind: directive creates two-way data bindings between elements and variables. bind:value on inputs syncs the value in real-time. bind:checked for checkboxes, bind:group for radio groups, and bind:files for file inputs. Each binding reflects changes instantly.
Form handling benefits from reactive declarations for validation. Svelte 5’s $state rune replaces the need for bind: in some cases. HTML form events work alongside bindings for complex form logic.
Reactivity with Runes (Svelte 5)
Svelte 5 introduces runes — explicit reactivity primitives that replace the old compiler magic. $state declares reactive state, $derived creates computed values, and $effect runs side effects. Runes work in .svelte files and .svelte.js modules, unifying reactivity across component and non-component code.
Runes make reactivity explicit and predictable. $props replaces export let for component props. $state with .snapshot captures a non-reactive copy. The rune API improves TypeScript support and enables Svelte code in plain JavaScript modules.
{title}
Count: {count} (doubled {doubled})
{#each user.todos as todo}
{todo.text}
{/each}
Frequently Asked Questions
What makes Svelte different from React?
Svelte is a compiler that converts components into pure JavaScript at build time. There is no virtual DOM, no runtime library, and no hook rules. Svelte apps are smaller, faster, and require less code than equivalent React apps.
Should I learn Svelte 4 or Svelte 5 in 2026?
Learn Svelte 5. Svelte 5 is the current major version with runes providing explicit reactivity. It builds on Svelte 4 concepts but offers better TypeScript integration and a unified reactivity model.
How large are Svelte applications?
Svelte apps are among the smallest. A basic Svelte component adds ~1.5KB gzipped. The runtime is essentially zero — most of Svelte is compiled away. Bundle size scales linearly with component count.
Does Svelte have a component library ecosystem?
Yes. Svelte has growing ecosystem support: Skeleton UI, shadcn-svelte, Melt UI, and Smelte provide pre-built components. The Svelte ecosystem is smaller than React but actively growing.
Originally published on Ayodhyyya. Last updated June 1, 2026.