@xstate/svelte
The @xstate/svelte package contains utilities for using XState with Svelte.
Quick start​
- Install xstateand@xstate/svelte:
npm i xstate @xstate/svelte
Via CDN
<script src="https://unpkg.com/@xstate/svelte/dist/xstate-svelte.min.js"></script>
By using the global variable XStateSvelte
or
<script src="https://unpkg.com/@xstate/svelte/dist/xstate-svelte.fsm.min.js"></script>
By using the global variable XStateSvelteFSM
- Import useMachine
<script>
  import { useMachine } from '@xstate/svelte';
  import { createMachine } from 'xstate';
  const toggleMachine = createMachine({
    id: 'toggle',
    initial: 'inactive',
    states: {
      inactive: {
        on: { TOGGLE: 'active' }
      },
      active: {
        on: { TOGGLE: 'inactive' }
      }
    }
  });
  const { state, send } = useMachine(toggleMachine);
</script>
<button on:click={() => send('TOGGLE')}>
  {$state.value === 'inactive'
    ? 'Click to activate'
    : 'Active! Click to deactivate'}
</button>
API​
useMachine(machine, options?)​
A function that creates an actor from the given machine and starts a service that runs for the lifetime of the component.
Arguments
- machine- An XState machine.
- options(optional) - Actor options OR one of the following Machine Config options:- guards,- actions,- activities,- services,- delays,- immediate,- context, or- state.
Returns { state, send, service}:
- state- A Svelte store representing the current state of the machine as an XState- Stateobject. You should reference the store value by prefixing with- $i.e.- $state.
- send- A function that sends events to the running service.
- service- The created service.
useMachine(machine) with @xstate/fsm​
A function that creates an actor from the given finite state machine from [@xstate/fsm] and starts a service that runs for the lifetime of the component.
This special useMachine hook is imported from @xstate/svelte/lib/fsm
Arguments
- machine- An XState finite state machine (FSM).
Returns an object {state, send, service}:
- state- A Svelte store representing the current state of the machine as an- @xstate/fsm- StateMachine.Stateobject. You should reference the store value by prefixing with- $i.e.- $state.
- send- A function that sends events to the running service.
- service- The created- @xstate/fsmservice.
Example
<script>
  import { useMachine } from '@xstate/svelte/lib/fsm';
  import { createMachine, assign } from '@xstate/fsm';
  const fetchMachine = createMachine({
    id: 'fetch',
    initial: 'idle',
    context: {
      data: undefined
    },
    states: {
      idle: {
        on: { FETCH: 'loading' }
      },
      loading: {
        entry: ['load'],
        on: {
          RESOLVE: {
            target: 'success',
            actions: assign({
              data: (context, event) => event.data
            })
          }
        }
      },
      success: {}
    }
  });
  const onFetch = () => new Promise((res) => res('some data'));
  const { state, send } = useMachine(fetchMachine, {
    actions: {
      load: () => {
        onFetch().then((res) => {
          send({ type: 'RESOLVE', data: res });
        });
      }
    }
  });
</script>
{#if $state.value === 'idle'}
  <button on:click={() => send('FETCH')}>Fetch</button>
{:else if $state.value === 'loading'}
  <div>Loading...</div>
{:else if $state.value === 'success'}
  <div>
    Success! Data: <div data-testid="data">{$state.context.data}</div>
  </div>
{/if}
useSelector(actor, selector, compare?, getSnapshot?)​
A function that returns Svelte store representing the selected value from the snapshot of an actor, such as a service. The store will only be updated when the selected value changes, as determined by the optional compare function.
Arguments
- actor- a service or an actor-like object that contains- .send(...)and- .subscribe(...)methods.
- selector- a function that takes in an actor’s "current state" (snapshot) as an argument and returns the desired selected value.
- compare(optional) - a function that determines if the current selected value is the same as the previous selected value.
Example
<script lang="ts">
  import { createActor } from 'xstate';
  import { createModel } from 'xstate/lib/model';
  import { useSelector } from '../src';
  const model = createModel(
    {
      count: 0,
      anotherCount: 0
    },
    {
      events: {
        INCREMENT: () => ({}),
        INCREMENT_ANOTHER: () => ({})
      }
    }
  );
  const machine = model.createMachine({
    initial: 'idle',
    context: model.initialContext,
    states: {
      idle: {
        on: {
          INCREMENT: {
            actions: model.assign({ count: ({ count }) => count + 1 })
          },
          INCREMENT_ANOTHER: {
            actions: model.assign({
              anotherCount: ({ anotherCount }) => anotherCount + 1
            })
          }
        }
      }
    }
  });
  const service = createActor(machine).start();
  const count = useSelector(service, (state) => state.context.count);
  let withSelector = 0;
  $: $count && withSelector++;
  let withoutSelector = 0;
  $: $service.context.count && withoutSelector++;
</script>
<button data-testid="count" on:click={() => service.send('INCREMENT')}
  >Increment count</button
>
<button data-testid="another" on:click={() => service.send('INCREMENT_ANOTHER')}
  >Increment another count</button
>
<div data-testid="withSelector">{withSelector}</div>
<div data-testid="withoutSelector">{withoutSelector}</div>
Configuring Machines​
Existing machines can be configured by passing the machine options as the 2nd argument of useMachine(machine, options).
Example: the 'fetchData' service and 'notifySuccess' action are both configurable:
<script>
  import { useMachine } from '@xstate/svelte';
  import { createMachine, assign } from 'xstate';
  const fetchMachine = createMachine({
    id: 'fetch',
    initial: 'idle',
    context: {
      data: undefined,
      error: undefined
    },
    states: {
      idle: {
        on: { FETCH: 'loading' }
      },
      loading: {
        invoke: {
          src: 'fetchData',
          onDone: {
            target: 'success',
            actions: assign({
              data: (_, event) => event.data
            })
          },
          onError: {
            target: 'failure',
            actions: assign({
              error: (_, event) => event.data
            })
          }
        }
      },
      success: {
        entry: 'notifySuccess',
        type: 'final'
      },
      failure: {
        on: {
          RETRY: 'loading'
        }
      }
    }
  });
  const onResolve = (data) => {
    // Do something with data
  };
  const { state, send } = useMachine(fetchMachine, {
    actions: {
      notifySuccess: (context) => onResolve(context.data)
    },
    services: {
      fetchData: (_, event) =>
        fetch(`some/api/${event.query}`).then((res) => res.json())
    }
  });
</script>
{#if $state.value === 'idle'}
  <button on:click={() => send({ type: 'FETCH', query: 'something' })}>
    Search for something
  </button>
{:else if $state.value === 'loading'}
  <div>Searching...</div>
{:else if $state.value === 'success'}
  <div>Success! Data: {$state.context.data}</div>
{:else if $state.value === 'failure'}
  <p>{$state.context.error.message}</p>
  <button on:click={() => send('RETRY')}>Retry</button>
{/if}
Matching States​
When using hierarchical and parallel machines, the state values will be objects, not strings. In this case, it is best to use state.matches(...).
{#if $state.matches('idle')}
  //
{:else if $state.matches({ loading: 'user' })}
  //
{:else if $state.matches({ loading: 'friends' })}
  //
{/if}
Persisted and Rehydrated State​
You can persist and rehydrate state with useMachine(...) via options.state:
// Get the persisted state config object from somewhere, e.g. localStorage
const persistedState = JSON.parse(
  localStorage.getItem('some-persisted-state-key'),
);
const { state, send } = useMachine(someMachine, {
  state: persistedState,
});
// state will initially be that persisted state, not the machine’s initialState
Services​
XState services implement the Svelte store contract. Existing services and spawned actors can therefore be accessed directly and subscriptions are handled automatically by prefixing the service name with $.
Example:
// service.js
import { createMachine, createActor } from 'xstate';
const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' },
    },
    active: {
      on: { TOGGLE: 'inactive' },
    },
  },
});
export const toggleService = createActor(toggleMachine).start();
// App.svelte
<script>
  import { toggleService } from './service';
</script>
<button on:click={() => toggleService.send('TOGGLE')}>
  {$toggleService.value === 'inactive'
    ? 'Click to activate'
    : 'Active! Click to deactivate'}
</button>