createMachine, from the minimal toggle machine up to a fully featured counter with typed schema, computed values, refs, and effects.
Machine fundamentals
A state machine models stateful behavior using:- A finite set of states
- Transitions between those states, triggered by events
- Actions that execute during transitions
- Context — reactive data that changes over time
Minimal toggle machine
Connecting to the DOM
Theconnect function bridges machine state to element props. It reads from service.state and dispatches events via service.send:
Using it in a framework
Nested states
A state can contain child states by nesting astates map and declaring an initial child state. Use dot notation to target nested states in transitions.
Context
Context holds the reactive state of your machine — values that change over time and drive re-renders. Declare context using thebindable pattern, which provides built-in controlled/uncontrolled state management.
Bindable options
| Option | Description |
|---|---|
defaultValue | Initial value for uncontrolled usage |
value | Controlled value (when defined, the machine reflects this value) |
onChange | Callback invoked when the value changes |
isEqual | Custom equality function (defaults to Object.is) |
hash | Custom hash function for change detection |
sync | Whether to use synchronous updates (framework-specific) |
Reading and writing context
Props
Props are the configuration your machine accepts from users. Theprops function normalizes them and sets defaults.
prop function:
Computed
Computed values are derived from context, props, refs, or other computed values. They are recalculated on demand and memoized by the framework.Refs
Refs store non-reactive references — class instances, DOM nodes, timers, caches — that do not need to trigger re-renders.| Use refs when | Use context when |
|---|---|
| The value does not affect rendering | The value drives UI updates |
| You need a class instance or timer ID | You need controlled/uncontrolled support |
| Storing cached or intermediate values | Consumers need to read or set the value |
Watch
Thewatch function lets you reactively respond to prop or context changes. Use track to declare dependencies; the callback runs whenever any dependency changes.
track is implemented using each framework’s native reactivity (useEffect in React, createEffect in Solid, watch in Vue, reactive statements in Svelte), so it integrates naturally with your framework’s change detection.
Scope
Scope provides framework-agnostic access to DOM utilities. It is available inprops, actions, guards, computed, and effects.
Actions, guards, and effects
Actions
Actions update context or fire callbacks. They run during state transitions (viaentry, exit, or on handlers) or in response to watch triggers.
Guards
Guards are boolean functions that determine whether a transition should proceed.createGuards:
Effects
Effects run while a machine is in a given state and must return a cleanup function (orundefined). They are called when entering the state and cleaned up when exiting it or when the machine unmounts.
Full example: counter machine
TypeScript schema reference
| Field | Type | Description |
|---|---|---|
state | string union | All valid state names (e.g. "idle" | "active") |
props | interface | User-facing configuration accepted by the machine |
context | Record<string, any> | Reactive values stored in the machine |
refs | Record<string, any> | Non-reactive references |
computed | Record<string, any> | Derived values |
event | { type: string } & ... | Event object shape (usually EventObject) |
action | string | Action name union (usually string) |
guard | string | Guard name union (usually string) |
effect | string | Effect name union (usually string) |
tag | string | Optional state tag union for semantic grouping |