When state needs to be shared across multiple components — not just between parent and child — Svelte provides stores: reactive containers that any component can subscribe to.
Writable Stores
// src/lib/stores.js
import { writable } from 'svelte/store';
export const count = writable(0);
export const theme = writable('light');
export const cart = writable([]);Subscribe in a component with the $ auto-subscription prefix:
<script>
import { count } from '$lib/stores';
</script>
<!-- $count auto-subscribes and unsubscribes -->
<p>Count: {$count}</p>
<button on:click={()=> count.update(n=> n + 1)}>+</button>
<button on:click={()=> count.set(0)}>Reset</button>The $store syntax is Svelte compiler sugar — it calls store.subscribe() on mount and unsubscribe() on destroy automatically.
Derived Stores
Compute values from other stores:
import { derived } from 'svelte/store';
import { cart } from './stores';
export const cartTotal = derived(
cart,
$cart => $cart.reduce((sum, item) => sum + item.price * item.qty, 0)
);
export const cartCount = derived(
cart,
$cart => $cart.reduce((sum, item) => sum + item.qty, 0)
);<p>Total: £{$cartTotal.toFixed(2)}</p>
<p>Items: {$cartCount}</p>derived re-runs whenever cart changes.
Readable Stores
For values that update on their own (timers, sensor data):
import { readable } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => set(new Date()), 1000);
return function stop() { clearInterval(interval); };
});The second argument is a start function that runs when the first subscriber joins. It returns a stop function called when the last subscriber leaves.
Component Events
Child-to-parent communication uses createEventDispatcher:
<!-- TodoItem.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
export let todo;
const dispatch = createEventDispatcher();
</script>
<li>
<span>{todo.text}</span>
<button on:click={()=> dispatch('delete', todo.id)}>✕</button>
<button on:click={()=> dispatch('toggle', todo.id)}>✓</button>
</li>Parent listens with on:eventName:
<!-- TodoList.svelte -->
<script>
import TodoItem from './TodoItem.svelte';
let todos = [{ id: 1, text: 'Learn Svelte', done: false }];
function deleteTodo(e) { todos = todos.filter(t => t.id !== e.detail) }
function toggleTodo(e) { todos = todos.map(t => t.id === e.detail ? {...t, done: !t.done} : t) }
</script>
{#each todos as todo}
<TodoItem {todo} on:delete={deleteTodo} on:toggle={toggleTodo} />
{/each}
Store-Driven Todo List
Binding to Store Values
You can two-way bind directly to a store:
<script>
import { theme } from '$lib/stores';
</script>
<select bind:value={$theme}>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<p>Current theme: {$theme}</p>Assigning $theme = 'dark' calls theme.set('dark') under the hood.