Stack-based navigation for React — designed to live inside a container, not own the page.
flow-stack is a React library for push/pop navigation inside an existing UI container — a sidebar, a sheet, a modal, an expandable panel, or any fixed-size region. It manages the entry stack, animated scene transitions, and route params, while leaving layout, sizing, and the outer shell entirely up to you.
Most React navigation libraries assume they own the URL or the full viewport. flow-stack makes no such assumption. It is headless by default: bring your own container, mount it wherever you need it, and use as many independent stacks on one screen as you like.
- Push / pop / replace / reset — full navigation action set with direction awareness
- Param-driven screens — typed params per route, with optional defaults
- Route guards — async
canEnter/canLeaveper route; returnfalse(or a rejected promise) to block any navigation action - Animated transitions — 8 built-in presets, fully customisable via
translate,opacity,scale,easing,enterCurve,exitCurve,stagger - Priority-aware transition resolution — stack → route → action, with timing and style merged independently so
durationset at the stack level survives a string preset at the route level - Reduced motion —
reducedMotionprop on the provider; respectsprefers-reduced-motionby default - Multiple independent stacks — mount as many
NavigationStackProviderinstances as you need; each is fully isolated and identified by itsid - Controlled and uncontrolled — manage state externally or let the library own it
- Headless controller — use
createNavigationStackControlleroutside React for testing or state-machine integration - Accessibility — focus management and ARIA live regions out of the box
npm install flow-stackRequires React and react-dom ≥ 18.
import {
NavigationStackProvider,
NavigationStackScreen,
NavigationStackViewport,
useNavigationStack,
} from 'flow-stack';
function HomeScreen() {
const nav = useNavigationStack();
return <button onClick={() => nav.push('details', { id: '1' })}>Open</button>;
}
function DetailsScreen({ params }) {
const nav = useNavigationStack();
return (
<div>
<p>ID: {params.id}</p>
<button onClick={() => nav.pop()}>Back</button>
</div>
);
}
export function App() {
return (
<div style={{ width: 360, height: 600 }}>
<NavigationStackProvider id="main" initialRoute={{ name: 'home' }}>
<NavigationStackScreen name="home" component={HomeScreen} />
<NavigationStackScreen name="details" component={DetailsScreen} />
<NavigationStackViewport />
</NavigationStackProvider>
</div>
);
}| Concept | Description |
|---|---|
| Provider | Owns the stack state. One per independent navigation context. |
| Screen | Declares a named route and its component. |
| Viewport | Renders the visible scenes and runs transitions. Separate from the provider so you can position it freely. |
| Scene | Individual scene container rendered by the viewport. Exposed for custom renderScene implementations. |
| Controller | The headless state machine. The provider wraps one internally; you can also create one directly. |
useNavigationStack |
Hook that gives any component inside the provider access to push, pop, replace, reset, and the current state. |
Transitions are resolved in priority order: action options → route-level transition → stack-level transition → built-in fallback. Timing fields (duration, easing, enterCurve, exitCurve, stagger) and style fields (preset, translate, opacity, scale) are merged independently so you can mix a string preset at the route level with a custom duration at the stack level.
Examples coming soon. In the meantime, see the Quick start above or browse the source on GitHub.
Deeper documentation (transitions, controlled mode, accessibility, headless controller) is in progress. Questions and requests are welcome on the GitHub issues page.
Components
| Name | Purpose |
|---|---|
NavigationStackProvider |
Stack state, route registry, transition resolution |
NavigationStackViewport |
Scene renderer and animator |
NavigationStackScreen |
Declarative route definition (child of provider) |
NavigationStackScene |
Scene container element; used when implementing a custom renderScene callback |
Hooks
| Name | Returns |
|---|---|
useNavigationStack |
Full controller — push, pop, replace, reset, setParams, state, and more |
useNavigationEntry |
Active entry snapshot — entry, routeName, params, entryKey, index, isRoot |
useNavigationTransitions |
Live transition state — phase, direction, anchor, isReducedMotion |
Headless
| Name | Purpose |
|---|---|
createNavigationStackController |
Framework-independent navigation controller |
Pre-release (0.x). The public API is still evolving. Breaking changes may occur before 1.0.0. Feedback on the API surface is welcome.
Please see the CONTRIBUTING.md file for information on how to contribute to this repository.
This repository is licensed under the MIT License.