01 - State ($state)
What is $state?
$state() creates reactive state — when the value changes, the UI automatically updates. It replaces Svelte 4's implicit reactivity where all top-level let variables were reactive.
Svelte 4 (Legacy)
<script>
let count = 0; // all top-level let variables were automatically reactive
</script>Svelte 5
<script>
let count = $state(0); // explicitly opt-in to reactivity
</script>The difference: in Svelte 5, only variables wrapped in $state() are reactive. A plain let is just a regular JavaScript variable.
Basic Usage
<!-- src/lib/components/Counter.svelte -->
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>Clicks: {count}</button>Objects and Arrays
$state() has deep reactivity by default — mutating nested properties or array methods automatically triggers UI updates.
<!-- src/lib/components/UserProfile.svelte -->
<script>
let user = $state({ name: 'Alice', age: 25 });
let items = $state([1, 2, 3]);
</script>
<button onclick={() => user.age++}>Birthday</button> <!-- deep mutation tracked -->
<button onclick={() => items.push(items.length + 1)}>Add Item</button> <!-- array mutation tracked -->In Svelte 4, you had to reassign arrays/objects to trigger updates (items = [...items, newItem]). In Svelte 5, items.push() just works.
Key Points
- Replaces Svelte 4's implicit reactivity — now you explicitly opt-in with
$state() - Works with primitives, objects, and arrays
- Deep reactivity by default — nested mutations are tracked automatically
- Plain
letwithout$state()is not reactive
Interactive Example
<script>
let count = $state(0);
let user = $state({ name: 'Alice', age: 25 });
let items = $state([1, 2, 3]);
</script>
<div>
<h2>01 - State Example</h2>
<div>
<h3>Counter</h3>
<button onclick={() => count++}>Clicks: {count}</button>
<button onclick={() => count = 0}>Reset</button>
</div>
<div>
<h3>Object State</h3>
<p>Name: {user.name}, Age: {user.age}</p>
<button onclick={() => user.age++}>Birthday</button>
<input bind:value={user.name} placeholder="Change name" />
</div>
<div>
<h3>Array State</h3>
<p>Items: {items.join(', ')}</p>
<button onclick={() => items.push(items.length + 1)}>Add Item</button>
<button onclick={() => items.pop()}>Remove Last</button>
</div>
</div>
<style>
div { margin: 20px; }
h3 { margin-top: 20px; }
button { margin: 5px; }
</style>