Svelte logo

Svelte by Example: Readable Stores

A readable store is a store that can be subscribed to, but not updated from a component. Readable stores are useful for subscribing to external data.

In this example, we'll change our todo list's theme when the user's preferred color scheme changes.

Svelte exposes a readable function to create readable stores.

Pass an initial value and a start function. The start function runs when the first subscriber arrives.

Access browser APIs inside the start function, not at module scope. The guard also makes the store safe to subscribe to on the server.

Set the current theme, then listen for changes.

Return a cleanup function. It runs when the last subscriber leaves.

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


export const theme = readable('light', (set) => {





  if (typeof window === 'undefined') return;
  const query = window.matchMedia(
    '(prefers-color-scheme: dark)',
  );


  function update() {
    set(query.matches ? 'dark' : 'light');
  }
  update();
  query.addEventListener('change', update);

  return () => query.removeEventListener('change', update);
});

Start with the same theme on the server and in the browser, so the markup matches during hydration.

Subscribe in onMount to apply the user's preference after mounting. Returning the unsubscribe function cleans up when the component is removed.

TodoList.svelte
<script>
  import { onMount } from 'svelte';
  import { theme } from './stores.js';

  let currentTheme = $state('light');





  onMount(() => theme.subscribe((value) => {
    currentTheme = value;
  }));
</script>

<section class:dark={currentTheme === 'dark'}>
  <h1>Todo List</h1>
  <!-- … -->
</section>