useStack

useStack returns the full state of the nearest <Stack> navigator on web, for building a completely custom stack layout - your own header, transitions, back button, anything.

<Stack> already renders headless on web by default (just the focused screen); reach for useStack when you want to render something yourself instead. See the headless web navigators guide for the full picture.

Usage

Place your component as a child of <Stack>. It replaces the headless default on web and is ignored on native, so the same layout file works everywhere:

// app/_layout.tsx, works on both platforms
import { Stack, useRouter, useStack } from 'one'
function WebStackLayout() {
const { screens, focused } = useStack()
const router = useRouter()
return (
<>
{screens.length > 1 && <button onClick={router.back}>← Back</button>}
<h1>{focused.options.title}</h1>
{focused.element}
</>
)
}
export default function Layout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: 'Feed' }} />
<Stack.Screen name="[id]" options={{ title: 'Post' }} />
<WebStackLayout />
</Stack>
)
}

Return value

PropertyTypeDescription
screensScreenEntry[]Every screen currently in the stack, in stack order.
focusedScreenEntryThe currently focused screen.

useStack is a state reader. To navigate, use useRouter / router and Link as you would anywhere else in the app - every entry carries an href.

ScreenEntry

PropertyTypeDescription
keystringUnique per-instance key.
namestringThe route name, matching the file name in app/.
paramsobjectThe route’s params.
hrefstringThe resolved path for this screen.
isFocusedbooleanWhether this is the focused screen.
keepMountedbooleanWhether options.keepMounted was set.
optionsobjectThe compiled options for this screen (title, presentation, and anything else set via Stack.Screen).
elementReactElementThe screen’s rendered content. Rendering it mounts the route.

Presentation screens

Screens with a presentation option (sheet, modal, formSheet, …) still show up in screens alongside regular pushed screens - useStack doesn’t separate them out. If your custom layout needs to treat them differently, check focused.options.presentation. Most apps handle presentation screens with Presentations instead, which is scoped specifically to them.

Edit this page on GitHub.