react-screen-flow

Core Concepts

Screens

Screens are a typed map of screen IDs to React components or string IDs. Keys become the valid screen IDs for the whole flow, so invalid targets like "settings" are caught at compile time.

Pass React.lazy components the same way — wrap <ScreenComponent /> in Suspense in your app.

External State

The library does not own app state. Pass state into the hook:

useScreenFlow(flowDefinition, state);

That works with React state, Zustand, Redux, server data, React Router loaders, or any other source.

resolveStart

resolveStart(state) tells the flow where the user belongs based on current state. Useful for auth and profile flows where users refresh or deep link.

With autoNavigate: true, the hook re-runs this when external state changes.

Transitions

Each screen can define:

next and prev can be functions, so branching stays in the flow definition instead of button handlers. All returned screen IDs are checked against the screens map.

Guards

Guards read state your app already provides and return a boolean or a decision object:

canGoNext: (state) => Boolean(state.user);

canGoNext: () => ({
  allowed: false,
  message: "Session expired.",
  redirectTo: "login",
  code: "SESSION_EXPIRED",
});

Fetch requests, login calls, payment validation, and state updates belong in your app actions, loaders, effects, or store logic — not inside flow declarations.

Why Use This?

react-screen-flow is smaller than a state machine and more focused than a router. It fits when you need typed screen flows with guards, async checks, and loading behavior, without the library owning app state or URL routing.

Tool Best At Where react-screen-flow Fits
React Router / TanStack Router URLs, nested layouts, route loaders. Router for URLs; this library for which screen is allowed.
XState / Zag / Robot Full state machines, events, parallel states. Screens plus guards, not a full statechart.
react-use-wizard / use-wizard Linear next/back wizard state. Branching, async guards, redirects, and refresh recovery.
Form libraries Multi-step form validation. Form state stays in the form; pass readiness into the flow.
Redux / Zustand / Jotai App-wide state. Store holds facts; flow reads state and returns decisions.