Lynx/Modules/Navigation/Stack
@sigx/lynx-navigation · Stable · Component library

Stack#

The stack navigator: a native push/pop stack of screens. In bound mode it renders the enclosing navigator's stack; in nested-owner mode it mints a fresh per-tab back-stack. Its default slot is chrome rendered inside the stack's nav scope — typically a Header.

Import#

TSX
import { Stack } from '@sigx/lynx-navigation';

Basic usage#

Mount a Stack inside a NavigationRoot — the root creates the navigator state, the stack renders its screens. Drop a <Header /> into the stack's default slot for the headless default header bar.

TSX
import { z } from 'zod';
import { defineRoutes, NavigationRoot, Stack, Header } from '@sigx/lynx-navigation';
import { Home } from './screens/Home';
import { Profile } from './screens/Profile';

export const routes = defineRoutes({
    home: { component: Home },
    profile: {
        component: Profile,
        params: z.object({ id: z.string() }),
        path: '/users/:id',
    },
});

declare module '@sigx/lynx-navigation' {
    interface Register {
        routes: typeof routes;
    }
}

export const App = () => (
    <NavigationRoot routes={routes} initialRoute="home">
        <Stack>
            <Header />
        </Stack>
    </NavigationRoot>
);

This is bound mode — with no initialRoute, the stack renders the enclosing navigator's stack. useNav() inside returns that navigator. card pushes stay local; modal / fullScreen / transparent-modal / sheet presentations escalate to root; replace is strictly local.

Nested per-tab stacks#

Passing initialRoute puts the stack in nested-owner mode: it mints a fresh nested navigator with its own back-stack. This is how each tab gets independent history — useNav() inside returns the nested nav, and nav.parent is the enclosing one.

TSX
import { Tabs, TabBar, Stack, Header } from '@sigx/lynx-navigation';

export const Main = () => (
    <Tabs initialTab="trips">
        <Tabs.Screen name="trips" label="Trips">
            <Stack initialRoute="tripsHome">
                <Header />
            </Stack>
        </Tabs.Screen>
        <Tabs.Screen name="account" label="Account">
            <Stack initialRoute="accountHome">
                <Header />
            </Stack>
        </Tabs.Screen>
        <TabBar />
    </Tabs>
);

Inside a tab, a card push (nav.push('tripDetail', { tripId })) stays in that tab's stack, while a modal push escalates to root and overlays the tab bar. See Tabs for the full pattern.

Bounding retained screens#

maxRetainedScreens caps how many covered card screens stay mounted underneath the top entry (default: all, capped at the internal MAX_LAYERS of 24). Lower it to trade transition fidelity for memory on deep stacks.

TSX
<Stack maxRetainedScreens={3}>
    <Header />
</Stack>

Props#

PropTypeDescription
initialRoutestringWhen set, switches to nested-owner mode — the stack mints a fresh nested navigator starting at this route. Omit for bound mode (renders the enclosing navigator's stack).
initialParamsRecord<string, unknown>Params for the nested navigator's initial route.
initialSearchRecord<string, unknown>Search / query params for the nested navigator's initial route.
maxRetainedScreensnumberBounds covered-card retention. Default: all, capped at MAX_LAYERS (24).

Slots#

SlotDescription
defaultChrome rendered inside this stack's nav scope — e.g. a per-stack <Header />.

See also#

  • Screen — declarative per-screen options and header slot fills.
  • Header — the default navigator header chrome.
  • API reference — full signature and the Nav handle from useNav.
  • Usage — the complete typed-routes setup pattern.