Stately
Get Started

Quick start

Start here to jump straight into XState and Stately Studio.

This quick start guide will help you get started with XState and Stately Studio. You will learn how to create a state machine, create an actor from that state machine, send events to that actor, and observe the state changes.

The fastest way to start with Stately Studio is to go to state.new. There, you’ll find a starter machine with all the statechart basics ready for you to edit. Read more about Stately Studio.

Installing XState v5

XState is a visual state management and orchestration library for JavaScript and TypeScript.

Install the XState v5 using your preferred package manager:

npm install xstate
pnpm install xstate
yarn add xstate

XState v5 requires TypeScript version 5.0 or greater.

For best results, use the latest TypeScript version. Read more about XState and TypeScript

Create a machine

In XState, a machine is an object that contains all the logic for an actor. In this example, we will create a simple toggle machine that can be in one of two states: Active or Inactive. The toggle event will toggle the state between Active and Inactive.

import { createMachine } from 'xstate';

const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'Inactive',
  states: {
    Inactive: {
      on: { toggle: 'Active' },
    },
    Active: {
      on: { toggle: 'Inactive' },
    },
  },
});

Read our introduction to state machines and statecharts to familiarize yourself with the concepts.

Create an actor and send events

Machine logic can be used to create an actor. An actor is a running process that can receive messages (events), send messages and change its behavior based on the messages it receives.

import { createMachine, createActor } from 'xstate';

const toggleMachine = createMachine({
  // Machine code from above
});

// Create an actor that you can send events to.
// Note: the actor is not started yet!
const actor = createActor(toggleMachine);

// Subscribe to snapshots (emitted state changes) from the actor
actor.subscribe((snapshot) => {
  console.log('Value:', snapshot.value);
});

// Start the actor
actor.start(); // logs 'Inactive'

// Send events
actor.send({ type: 'toggle' }); // logs 'Active'
actor.send({ type: 'toggle' }); // logs 'Inactive'

Use delayed transitions

Delayed transitions are transitions that automatically happen after a specified interval of time.

export const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'Inactive',
  states: {
    Inactive: {
      on: { toggle: 'Active' },
    },
    Active: {
      on: { toggle: 'Inactive' },
      after: { 2000: 'Inactive' },
    },
  },
});

Handle context data

Context is how you store data in a state machine actor.

import { assign, createMachine } from 'xstate';

export const toggleMachine = createMachine({
  id: 'toggle',
  context: { count: 0 },
  initial: 'Inactive',
  states: {
    Inactive: {
      on: { toggle: 'Active' },
    },
    Active: {
      entry: assign({
        count: ({ context }) => context.count + 1,
      }),
      on: { toggle: 'Inactive' },
      after: { 2000: 'Inactive' },
    },
  },
});

Add input

Input is how initial data can be provided to a machine actor.

Guards are used to conditionally allow or disallow transitions.

import { assign, createMachine } from 'xstate';

export const toggleMachine = createMachine({
  id: 'toggle',
  context: ({ input }) => ({
    count: 0,
    maxCount: input.maxCount,
  }),
  initial: 'Inactive',
  states: {
    Inactive: {
      on: {
        toggle: {
          // Only trigger toggle transition if count is less than maxCount
          guard: ({ context }) => context.count < context.maxCount,
          target: 'Active',
        },
      },
    },
    Active: {
      entry: assign({
        count: ({ context }) => context.count + 1,
      }),
      on: { toggle: 'Inactive' },
      after: { 2000: 'Inactive' },
    },
  },
});

const actor = createActor(toggleMachine, {
  input: { maxCount: 10 },
});

actor.subscribe((snapshot) => {
  console.log('State:', snapshot.value);
});

actor.start();

actor.send({ type: 'toggle' });

Use your machine with a framework

import { useMachine } from '@xstate/react';
import { toggleMachine } from './toggleMachine';

const App = () => {
  const [state, send] = useMachine(toggleMachine);

  return (
    <div>
      <div>Value: {state.value}</div>
      <button onClick={() => send({ type: 'toggle' })}>Toggle</button>
    </div>
  );
};

On this page