Finite State Machines for UI flows

Finite State Machines for UI flows

TL;DR: Model UI as a small set of explicit states and transitions. This prevents impossible states and makes flows easier to test.

Why FSMs help

UI flows like onboarding wizards, multi-step forms, or auth can end up in invalid combinations. With an FSM, only defined transitions are allowed.

Simple statechart

states:
  idle -> loading on SUBMIT
  loading -> success on OK
  loading -> error on FAIL
  error -> idle on RETRY

Reducer-based FSM in React

const chart = {
  idle: { SUBMIT: "loading" },
  loading: { OK: "success", FAIL: "error" },
  error: { RETRY: "idle" },
  success: {}
};

function next(state, event) {
  return chart[state]?.[event] ?? state;
}

function Wizard() {
  const [state, setState] = React.useState("idle");
  const send = (evt) => setState(s => next(s, evt));
  // render by state
}

Guards and data

Transitions can have conditions. Keep state and context separate so tests can verify both.

Testing transitions

  • Assert the next state for each event.
  • Test guard conditions with both allowed and blocked inputs.

FAQ

Do I need a library
No. Start with a reducer. Adopt a library later if you need visualization and tooling.

Is this overkill for small components
If your component has more than a couple of boolean flags and branches, an FSM usually pays off.

Cast this in your project

Image credit: Photo by Pixabay: https://www.pexels.com/photo/gray-scale-photo-of-gears-159298/

Back to blog

Leave a comment

Please note, comments need to be approved before they are published.