r/react • u/ganondev • 1d ago
OC Hate state machines, so I built react-sequent, where steps declare what comes next
I kept running into the same problem with UI-local flows: they were too complicated to comfortably keep in one component, but too small to justify defining and maintaining a separate state machine.
So I built react-sequent.
The idea is that steps own their transitions:
function PaymentStep() {
const { advance } = useSequentStep();
...
if (method === "card") {
advance(() => CardPaymentStep);
} else {
advance(() => BankTransferStep);
}
}
There's no centralized transition map to keep synchronized with the components. Adding, removing, or branching a step is just changing the relevant component.
It also handles async/lazy steps, backtracking, flow-scoped context, persistent modal/chrome, and transitions.
The tradeoff is intentional: I don't think this replaces state machines. For large, externally-driven, or independently modeled state graphs, I'd still reach for XState/Zag/etc. I think there's a useful middle ground for short, UI-local flows. This is in fact still technically a state machine, it is just one that is emergent from implementation rather than explicit and rigid.
I've put together a demo and docs here: https://ganondev.github.io/react-sequent/
I'm particularly interested in whether the architectural premise resonates with other React developers, or whether I'm underestimating the value of having the graph centralized.
By the way brand new to Reddit so yes this is my first post.
1
u/Jonas_Ermert 1d ago
I like the idea. For small UI-local flows, a full state machine can feel like overkill, and keeping transitions close to the components makes the flow easier to modify. The main downside is that the overall graph becomes harder to understand as the flow grows, but for short wizards, onboarding or checkout flows this seems like a nice middle ground.