Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

State: $state

State is component data that changes while the page is open: text in a field, a list of tasks, a counter. For Svelte to update the page when it changes, the variable is declared with the $state rune.

A plain variable does not update the page

<!-- src/routes/+page.svelte -->
<script>
  let count = 0;
</script>
 
<button onclick={() => count++}>Done: {count}</button>

The onclick attribute sets a function that runs on click (more in the lesson on events). The number in the variable grows, but the button always shows "Done: 0": Svelte does not track plain variables.

The $state rune

<!-- src/routes/+page.svelte -->
<script>
  let count = $state(0);
</script>
 
<button onclick={() => count++}>Done: {count}</button>

Now each click increases the number on the button. $state(0) creates a reactive variable with the initial value 0. You read and change it like a regular variable — no .value and no setter functions.

Arrays and objects

State can hold an array of objects — for example, a list of tasks. Svelte notices changes inside it: push, assigning a property, splice.

<!-- src/routes/+page.svelte -->
<script>
  let todos = $state([
    { id: 1, text: 'Buy bread', done: false },
    { id: 2, text: 'Call Oleg', done: false }
  ]);
 
  function addTodo() {
    todos.push({ id: Date.now(), text: 'New task', done: false });
  }
 
  function finishFirst() {
    todos[0].done = true;
  }
</script>
 
<p>Tasks: {todos.length}</p>
<p>First one done: {todos[0].done ? 'yes' : 'no'}</p>
<button onclick={addTodo}>Add</button>
<button onclick={finishFirst}>Finish the first</button>

The "Add" button increases the task counter, the "Finish the first" button changes "no" to "yes". Svelte gives this deep reactivity to plain arrays and objects passed to $state.

Replacing the whole value

A state variable can be assigned a new value — that updates the page too:

<script>
  let todos = $state([{ id: 1, text: 'Buy bread', done: true }]);
 
  function clearDone() {
    todos = todos.filter((todo) => !todo.done);
  }
</script>
 
<p>Tasks: {todos.length}</p>
<button onclick={clearDone}>Remove finished</button>

After the click the finished task disappears and the counter shows "Tasks: 0".

Where $state is allowed

The rune works only when declaring a variable or a class field — in a .svelte component or in a .svelte.js file (covered in the chapter on shared state). In a plain .js file it does not work: the Svelte compiler does not process such files.

Common mistake

Declaring state with const and then assigning a new value:

<script>
  const todos = $state([]);
 
  function reset() {
    todos = []; // Error: cannot assign to a constant
  }
</script>

If the variable has to be replaced as a whole, declare it with let. const is fine when you only change the contents — call push or assign properties.

Thanks for reading!

Donate to the site — we work hard for you.