Skip to content

States & transitions

A machine is always in exactly one state. Events drive transitions between them.

import { machine } from '@dunky-dev/state-machine'
const light = machine({
initial: 'green',
context: {},
states: {
green: { on: { next: { target: 'yellow' } } },
yellow: { on: { next: { target: 'red' } } },
red: { on: { next: { target: 'green' } } },
},
})
light.start()
light.send({ type: 'next' })
light.state // 'yellow'

Put an event in the top-level on to handle it from any state. A per-state on wins if both match:

machine({
initial: 'a',
context: {},
on: { reset: { target: 'a' } }, // works from any state
states: {
a: {},
b: {},
c: {},
},
})

Tags group states so the view asks about a category instead of a specific name:

const m = machine({
initial: 'closed',
context: {},
states: {
closed: {},
opening: { tags: ['visible'] },
open: { tags: ['visible'] },
},
})
m.start()
m.hasTag('visible') // true while in 'opening' or 'open'
m.matches('open') // exact-state check

Events are queued. If an action sends another event, it waits until the current transition fully settles — no re-entrancy:

states: {
a: {
on: {
go: {
target: 'b',
actions: [({ send }) => send({ type: 'auto' })],
},
},
},
b: { on: { auto: { target: 'c' } } }, // 'auto' processes after the machine settles in 'b'
c: {},
}

States here are flat — no nesting, no parallel regions inside a single machine. When a component has two independent axes of state, compose two peer machines. See Peer machines and States.