Stately
XState v6 alpha

Transitions

Configure event, delayed, eventless and completion transitions.

A transition describes how a state responds to an event.

idle: { on: { start: { target: 'active' } } }

Transition properties

PropertyDescription
targetTarget state or states.
guardCondition that must pass.
reenterRe-enter the source state when targeting it.
descriptionHuman-readable description.

A targetless transition can update context and run effects without leaving the current state. Set reenter: true when a self-transition should run exit and entry behavior again.

on: {
  rename: ({ context, event }) => ({
    context: { ...context, name: event.name }
  }),
  restart: { target: 'active', reenter: true }
}

Transition functions

submit: ({ context, event }, enq) => {
  if (!context.valid) return;
  enq(() => console.log('Submitted', event));
  return {
    target: 'submitting',
    context: { ...context, submittedAt: Date.now() }
  };
}

Returning undefined prevents the transition.

always runs without an external event. after runs after a delay. onDone, onError and onTimeout handle actor outcomes.

Use targetless transitions for edits that keep a form on the same step. Use re-entering transitions to restart a timer, subscription or invoked request.

Put shared transitions on a parent state. A child can set an event to undefined to forbid that parent transition. Wildcards such as pointer.* match an event family when no exact transition matches.

on: {
  'pointer.*': { target: 'tracking' },
  '*': { target: 'unexpectedEvent' }
}

TypeScript

Transition targets are checked against authored state paths. Event schemas narrow event inside transition functions.

Transitions cheatsheet

on: { submit: { target: 'loading' } }
on: { rename: ({ context, event }) => ({ context: { ...context, name: event.name } }) }
on: { cancel: undefined }
always: { target: 'ready' }
after: { 1000: { target: 'idle' } }
onDone: { target: 'success' }
onError: { target: 'failure' }

On this page