Svelte logo

Svelte by Example: Custom Stores

Custom stores are useful to encapsulate data and expose specific functions to manage state. We can use Svelte's built-in store helpers as a starting point.

In this example, we'll create a custom todos store.

Create a writable store inside a factory function. Each call creates a separate store.

Our methods update the store without exposing set or update to components.

Return an object with subscribe and our methods. The writable helper supplies the store's subscription behavior for us.

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

export function createTodos() {
  const { subscribe, update } = writable([]);





  function addTodo(todo) {
    update((items) => [...items, todo]);
  }

  function checkTodo(index, completed) {
    update((items) => items.map((todo, i) =>
      i === index ? { ...todo, completed } : todo,
    ));
  }



  return { subscribe, addTodo, checkTodo };
}

A store's subscribe method immediately supplies the current value and returns an unsubscribe function.

Our AddTodo component calls onadd with { task, completed: false }. Our Todo component receives task and completed, and calls onchecked with a boolean. Both use callback props, not custom events.

Create a store for this component, and destructure its methods for easy access.

Use $todos to read the store value, just like a built-in store.

TodoList.svelte
<script>
  import Todo from './Todo.svelte';
  import AddTodo from './AddTodo.svelte';
  import { createTodos } from './stores.js';

  const todos = createTodos();
  const { addTodo, checkTodo } = todos;

  addTodo({ task: 'Walk dog', completed: false });
</script>



{#each $todos as todo, index}
  <Todo
    {...todo}
    onchecked={(completed) => checkTodo(index, completed)}
  />
{/each}

<AddTodo onadd={addTodo} />