Step navigation
For a wizard or guided flow, use a small step engine rather than a full router. It keeps one current step and lets Back follow the path the user actually took.
Create a flow and connect the buttons
Section titled “Create a flow and connect the buttons”The optional @jnreis/briojs/step entry (browser: brio.step.min.js) provides
createStepEngine({ initial, steps }), a small synchronous navigation engine
with exactly one current step and history-based Back. It owns its reactive
state: definitions are configuration, not a record of mutable active flags.
const wizard = brio.createStepEngine({ initial: 'intro', steps: { intro: { next: 'details' }, details: { next: 'review' }, review: {}, },});
const app = brio.createApp({ state: () => ({ wizard }),});app.mount('#app');<div id="app"> <p>Current: <span b-text="$data.wizard.current"></span></p> <section b-if="$data.wizard.isActive('intro')">Welcome</section> <section b-if="$data.wizard.isActive('details')">Enter your details</section> <section b-if="$data.wizard.isActive('review')">Review your answers</section> <button b-on-click="$data.wizard.back()" b-bind-disabled="!$data.wizard.canGoBack">Back</button> <button b-on-click="$data.wizard.next()" b-bind-disabled="!$data.wizard.canGoNext">Next</button> <button b-on-click="$data.wizard.go('review')">Jump to review</button> <button b-on-click="$data.wizard.reset()">Start over</button></div>Keep the engine in $data for local use. For intentional sharing, pass the same
instance through createApp({ stores: { wizard } }) and read $stores.wizard.
Neither pattern requires wrapping the definitions or engine in state().
Step engine API
Section titled “Step engine API”| API | Behavior |
|---|---|
current | Read-only reactive name of the current step. |
canGoNext | Read-only reactive boolean: the current definition has a next link. |
canGoBack | Read-only reactive boolean: history is nonempty. |
isActive(name) | Reactive current-name comparison; unknown names return false. |
go(name) | Navigate to a registered name and push the former current name; returns true. Invalid/unknown targets throw before mutation. |
next() | Follow the configured next link; return false without warning at a terminal step. |
back() | Pop history, without pushing another entry; return false without warning when empty. |
reset() | Restore initial and clear history; return true if current or history changed, otherwise false. |
History, cycles, and reset
Section titled “History, cycles, and reset”Back follows the actual path, not a configured reverse link. For example, Intro → Review → Back returns directly to Intro. After Back, further navigation records a new path; there is no Forward stack. History is private and unlimited until reset or the engine is released.
Cycles are allowed. Navigating to the current step is a successful no-op, with
no history entry or reactive notification. A self-linked step still has
canGoNext === true. Returning to the initial step through go() or a configured
link preserves history; only reset() clears it.
Step configuration rules
Section titled “Step configuration rules”Configuration is validated and copied once:
- Supply a nonempty plain-object
stepsrecord and an explicit registered initial name. - Each definition accepts only an optional nonempty
nextstring naming a registered step.{}is terminal. - Forward references, cycles, and exact literal names are supported.
- Unknown fields, accessors, malformed values, and dangling links throw.
- Keep labels/form data separately: definitions cannot contain
active,keep,back,origin, or business metadata. - Later changes to the input objects do not change the engine.
npm exports StepOptions, StepDefinition, StepRecord, and StepEngine.
Ownership and application workflow
Section titled “Ownership and application workflow”The facade and its methods are read-only. Navigation publishes a coherent final state even when called directly from JavaScript. Constructing an engine creates no effect or app-owned resource; disposing a consumer does not reset an engine shared with another app.
Reset affects navigation only, not form/application data. This utility has no dynamic registration, multiple-active mode, completion tracking, asynchronous guards, or hooks. Validate/await application work before navigating; manage loading, errors, and competing requests in that application workflow.