Frontend Patterns

Pattern

Form State Machine

Model form states (pristine, dirty, submitting, error) as explicit state transitions.

State Management Intermediate

Form State Machine

Problem

Form state logic becomes a tangled mess of boolean flags and conditional checks. A form can be both “submitting” and “dirty” or “validating” and “error”, but the code doesn’t prevent impossible states. Submit buttons stay enabled during submission, or validation runs after successful submission, creating bugs and race conditions.

Solution

Model form behavior as explicit states (editing, submitting, succeeded, failed) with defined transitions. This eliminates impossible states like simultaneously showing success and error messages.

Example

This example demonstrates modeling form submission as a state machine with explicit states and transitions to prevent impossible states.

// Define all possible states and their valid transitions
const formMachine = {
  idle: { SUBMIT: 'submitting' },                      // Can only submit from idle
  submitting: { SUCCESS: 'success', ERROR: 'error' },  // Can succeed or fail while submitting
  success: { RESET: 'idle' },                          // Can only reset from success
  error: { RETRY: 'submitting', RESET: 'idle' }        // Can retry or reset from error
};

const [state, setState] = useState('idle');
// Transition function enforces valid state changes only
const transition = (event) => setState(formMachine[state][event]);

Benefits

  • Eliminates impossible states by making valid transitions explicit and enforced.
  • Makes form behavior easier to reason about with clear state transitions.
  • Simplifies conditional rendering by replacing complex boolean logic with state checks.
  • Prevents race conditions and bugs from inconsistent state combinations.

Tradeoffs

  • Requires upfront design work to map out all states and transitions.
  • Can be overly complex for simple forms with straightforward validation.
  • May need a state machine library for complex forms, adding another dependency.
  • Takes time for developers unfamiliar with state machines to understand the pattern.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.