Expo Router Navigation

Navigation and routing for Expo Router

by expo · MIT license · ★ 2,657 on GitHub · v1.0.1

Expo Router Navigation cover

Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars,…

---
name: expo-router
description: Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars.
version: 1.0.1
license: MIT
---

# Expo Router Navigation

Navigation and routing for Expo Router apps. For screen styling, colors, controls, media, and visual effects, use the `expo-native-ui` skill; for motion and gestures, use `expo-animation`.

## References

Consult these resources as needed:

```
references/
  route-structure.md     Route conventions, dynamic routes, groups, folder organization

Overview

Navigation and routing for Expo Router apps. For screen styling, colors, controls, media, and visual effects, use the expo-native-ui skill; for motion and gestures, use expo-animation.

Manual install (npx, ZIP)
Claude Codenpx skills add expo/skills --skill expo-router -g -a claude-code
Claude Code (degit)npx degit expo/skills/plugins/expo/skills/expo-router#main ~/.claude/skills/expo-router
Claude.ai / desktopZip the folder and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md6.9 KB
Read SKILL.md here
expo/main1 file shown
SKILL.md
Show the full text241 lines

Expo Router Navigation

Navigation and routing for Expo Router apps. For screen styling, colors, controls, media, and visual effects, use the expo-native-ui skill; for motion and gestures, use expo-animation.

References

Consult these resources as needed:

references/
  route-structure.md     Route conventions, dynamic routes, groups, folder organization
  tabs.md                NativeTabs, migration from JS tabs, iOS 26 features
  toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)
  form-sheet.md          Form sheets in expo-router: configuration, footers and background interaction.
  search.md              Search bar with headers, useSearch hook, filtering patterns
  zoom-transitions.md    Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)

Code Style

  • Always use kebab-case for file names, e.g. comment-card.tsx
  • Always remove old route files when moving or restructuring navigation
  • Never use special characters in file names
  • Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.

Routes

See ./references/route-structure.md for detailed route conventions.

  • Routes belong in the app directory.
  • Never co-locate components, types, or utilities in the app directory. This is an anti-pattern.
  • Ensure the app always has a route that matches "/", it may be inside a group route.

Library Preferences

  • Color from expo-router for native semantic colors, not raw PlatformColor (type-safe, auto-adapts to light/dark). See expo-native-ui for the full color palette pattern.
  • In SDK 56+, never import from @react-navigation/* directly — use expo-router/react-navigation instead (covers @react-navigation/native, /core, /elements, /routers)

Behavior

  • Prefer Stack.SearchBar to add a search bar to a screen

Navigation

Use <Link href="/path" /> from 'expo-router' for navigation between routes.

import { Link } from 'expo-router';

// Basic link
<Link href="/path" />

// Wrapping custom components
<Link href="/path" asChild>
  <Pressable>...</Pressable>
</Link>

Whenever possible, include a <Link.Preview> to follow iOS conventions. Add context menus and previews frequently to enhance navigation.

Stack

  • ALWAYS use _layout.tsx files to define stacks
  • Use Stack from 'expo-router/stack' for native navigation stacks
Page Title

Set the page title with Stack.Title:

<Stack.Title>Home</Stack.Title>

Context Menus

Add long press context menus to Link components:

import { Link } from "expo-router";

<Link href="/settings" asChild>
  <Link.Trigger>
    <Pressable>
      <Card />
    </Pressable>
  </Link.Trigger>
  <Link.Menu>
    <Link.MenuAction
      title="Share"
      icon="square.and.arrow.up"
      onPress={handleSharePress}
    />
    <Link.MenuAction
      title="Block"
      icon="nosign"
      destructive
      onPress={handleBlockPress}
    />
    <Link.Menu title="More" icon="ellipsis">
      <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
      <Link.MenuAction
        title="Delete"
        icon="trash"
        destructive
        onPress={() => {}}
      />
    </Link.Menu>
  </Link.Menu>
</Link>;

Use link previews frequently to enhance navigation:

<Link href="/settings">
  <Link.Trigger>
    <Pressable>
      <Card />
    </Pressable>
  </Link.Trigger>
  <Link.Preview />
</Link>

Link preview can be used with context menus.

Modal

Present a screen as a modal:

<Stack.Screen name="modal" options={{ presentation: "modal" }} />

Prefer this to building a custom modal component.

Sheet

Present a screen as a dynamic form sheet:

<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>
  • Using contentStyle: { backgroundColor: "transparent" } makes the background liquid glass on iOS 26+.

Common route structure

A standard app layout with tabs and stacks inside each tab:

app/
  _layout.tsx — <NativeTabs />
  (index,search)/
    _layout.tsx — <Stack />
    index.tsx — Main list
    search.tsx — Search view
// app/_layout.tsx
import { NativeTabs } from "expo-router/unstable-native-tabs";
import { ThemeProvider, DarkTheme, DefaultTheme } from "expo-router/react-navigation";
import { useColorScheme } from "react-native";

export default function Layout() {
  const colorScheme = useColorScheme();
  return (
    <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
      <NativeTabs>
        <NativeTabs.Trigger name="(index)">
          <NativeTabs.Trigger.Icon sf="list.dash" md="list" />
          <NativeTabs.Trigger.Label>Items</NativeTabs.Trigger.Label>
        </NativeTabs.Trigger>
        <NativeTabs.Trigger name="(search)" role="search" />
      </NativeTabs>
    </ThemeProvider>
  );
}

Create a shared group route so both tabs can push common screens:

// app/(index,search)/_layout.tsx
import { Stack } from "expo-router/stack";
import { colors } from "@/theme/colors";

export default function Layout({ segment }) {
  const screen = segment.match(/\((.*)\)/)?.[1]!;
  const titles: Record<string, string> = { index: "Items", search: "Search" };

  return (
    <Stack
      screenOptions={{
        headerTransparent: true,
        headerShadowVisible: false,
        headerLargeTitleShadowVisible: false,
        headerLargeStyle: { backgroundColor: "transparent" },
        headerTitleStyle: { color: colors.label },
        headerLargeTitleEnabled: true,
        headerBlurEffect: "none",
        headerBackButtonDisplayMode: "minimal",
      }}
    >
      <Stack.Screen name={screen} options={{ title: titles[screen] }} />
      <Stack.Screen name="i/[id]" options={{ headerLargeTitleEnabled: false }} />
    </Stack>
  );
}

headerLargeTitleEnabled is the SDK 56+ option name; older SDKs use headerLargeTitle, which is deprecated upstream.

Submitting Feedback

If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:

npx --yes submit-expo-feedback@latest --category skills --subject "expo-router" "<actionable feedback>"

Only submit when you have something specific and actionable to report. Include as much relevant context as possible. If an AI agent repeatedly failed or the user had to take over an Expo task, load the expo-skill-feedback skill and follow its eval-candidate flow instead of reusing the command above.

1---
2name: expo-router
3description: Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars.
4version: 1.0.1
5license: MIT
6---
7 
8# Expo Router Navigation
9 
10Navigation and routing for Expo Router apps. For screen styling, colors, controls, media, and visual effects, use the `expo-native-ui` skill; for motion and gestures, use `expo-animation`.
11 
12## References
13 
14Consult these resources as needed:
15 
16```
17references/
18 route-structure.md Route conventions, dynamic routes, groups, folder organization
19 tabs.md NativeTabs, migration from JS tabs, iOS 26 features
20 toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)
21 form-sheet.md Form sheets in expo-router: configuration, footers and background interaction.
22 search.md Search bar with headers, useSearch hook, filtering patterns
23 zoom-transitions.md Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)
24```
25 
26## Code Style
27 
28- Always use kebab-case for file names, e.g. `comment-card.tsx`
29- Always remove old route files when moving or restructuring navigation
30- Never use special characters in file names
31- Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.
32 
33## Routes
34 
35See `./references/route-structure.md` for detailed route conventions.
36 
37- Routes belong in the `app` directory.
38- Never co-locate components, types, or utilities in the app directory. This is an anti-pattern.
39- Ensure the app always has a route that matches "/", it may be inside a group route.
40 
41## Library Preferences
42 
43- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark). See `expo-native-ui` for the full color palette pattern.
44- In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`)
45 
46## Behavior
47 
48- Prefer `Stack.SearchBar` to add a search bar to a screen
49 
50# Navigation
51 
52## Link
53 
54Use `<Link href="/path" />` from 'expo-router' for navigation between routes.
55 
56```tsx
57import { Link } from 'expo-router';
58 
59// Basic link
60<Link href="/path" />
61 
62// Wrapping custom components
63<Link href="/path" asChild>
64 <Pressable>...</Pressable>
65</Link>
66```
67 
68Whenever possible, include a `<Link.Preview>` to follow iOS conventions. Add context menus and previews frequently to enhance navigation.
69 
70## Stack
71 
72- ALWAYS use `_layout.tsx` files to define stacks
73- Use Stack from 'expo-router/stack' for native navigation stacks
74 
75### Page Title
76 
77Set the page title with `Stack.Title`:
78 
79```tsx
80<Stack.Title>Home</Stack.Title>
81```
82 
83## Context Menus
84 
85Add long press context menus to Link components:
86 
87```tsx
88import { Link } from "expo-router";
89 
90<Link href="/settings" asChild>
91 <Link.Trigger>
92 <Pressable>
93 <Card />
94 </Pressable>
95 </Link.Trigger>
96 <Link.Menu>
97 <Link.MenuAction
98 title="Share"
99 icon="square.and.arrow.up"
100 onPress={handleSharePress}
101 />
102 <Link.MenuAction
103 title="Block"
104 icon="nosign"
105 destructive
106 onPress={handleBlockPress}
107 />
108 <Link.Menu title="More" icon="ellipsis">
109 <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
110 <Link.MenuAction
111 title="Delete"
112 icon="trash"
113 destructive
114 onPress={() => {}}
115 />
116 </Link.Menu>
117 </Link.Menu>
118</Link>;
119```
120 
121## Link Previews
122 
123Use link previews frequently to enhance navigation:
124 
125```tsx
126<Link href="/settings">
127 <Link.Trigger>
128 <Pressable>
129 <Card />
130 </Pressable>
131 </Link.Trigger>
132 <Link.Preview />
133</Link>
134```
135 
136Link preview can be used with context menus.
137 
138## Modal
139 
140Present a screen as a modal:
141 
142```tsx
143<Stack.Screen name="modal" options={{ presentation: "modal" }} />
144```
145 
146Prefer this to building a custom modal component.
147 
148## Sheet
149 
150Present a screen as a dynamic form sheet:
151 
152```tsx
153<Stack.Screen
154 name="sheet"
155 options={{
156 presentation: "formSheet",
157 sheetGrabberVisible: true,
158 sheetAllowedDetents: [0.5, 1.0],
159 contentStyle: { backgroundColor: "transparent" },
160 }}
161/>
162```
163 
164- Using `contentStyle: { backgroundColor: "transparent" }` makes the background liquid glass on iOS 26+.
165 
166## Common route structure
167 
168A standard app layout with tabs and stacks inside each tab:
169 
170```
171app/
172 _layout.tsx — <NativeTabs />
173 (index,search)/
174 _layout.tsx — <Stack />
175 index.tsx — Main list
176 search.tsx — Search view
177```
178 
179```tsx
180// app/_layout.tsx
181import { NativeTabs } from "expo-router/unstable-native-tabs";
182import { ThemeProvider, DarkTheme, DefaultTheme } from "expo-router/react-navigation";
183import { useColorScheme } from "react-native";
184 
185export default function Layout() {
186 const colorScheme = useColorScheme();
187 return (
188 <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
189 <NativeTabs>
190 <NativeTabs.Trigger name="(index)">
191 <NativeTabs.Trigger.Icon sf="list.dash" md="list" />
192 <NativeTabs.Trigger.Label>Items</NativeTabs.Trigger.Label>
193 </NativeTabs.Trigger>
194 <NativeTabs.Trigger name="(search)" role="search" />
195 </NativeTabs>
196 </ThemeProvider>
197 );
198}
199```
200 
201Create a shared group route so both tabs can push common screens:
202 
203```tsx
204// app/(index,search)/_layout.tsx
205import { Stack } from "expo-router/stack";
206import { colors } from "@/theme/colors";
207 
208export default function Layout({ segment }) {
209 const screen = segment.match(/\((.*)\)/)?.[1]!;
210 const titles: Record<string, string> = { index: "Items", search: "Search" };
211 
212 return (
213 <Stack
214 screenOptions={{
215 headerTransparent: true,
216 headerShadowVisible: false,
217 headerLargeTitleShadowVisible: false,
218 headerLargeStyle: { backgroundColor: "transparent" },
219 headerTitleStyle: { color: colors.label },
220 headerLargeTitleEnabled: true,
221 headerBlurEffect: "none",
222 headerBackButtonDisplayMode: "minimal",
223 }}
224 >
225 <Stack.Screen name={screen} options={{ title: titles[screen] }} />
226 <Stack.Screen name="i/[id]" options={{ headerLargeTitleEnabled: false }} />
227 </Stack>
228 );
229}
230```
231 
232`headerLargeTitleEnabled` is the SDK 56+ option name; older SDKs use `headerLargeTitle`, which is deprecated upstream.
233 
234## Submitting Feedback
235If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:
236```bash
237npx --yes submit-expo-feedback@latest --category skills --subject "expo-router" "<actionable feedback>"
238```
239Only submit when you have something specific and actionable to report. Include as much relevant context as possible.
240If an AI agent repeatedly failed or the user had to take over an Expo task, load the expo-skill-feedback skill and follow its eval-candidate flow instead of reusing the command above.
241 
View all files on GitHub →

Details

Version
1.0.1
License
MIT
Stars on the repo
★ 2,657
Checked
Source
expo/skills ↗
Creator
expo · 23 listings
View creator

Similar skills

See all →
SkillExpo Task Routerexpo/skills · by expoEntry point and router for every Expo or EAS task. Load this skill first — before writing code and before choosing another expo-* / eas-* skill — when the request, PRD, or spec mentions Expo, EAS, Expo Go, or an expo-* package, or the project has an `expo` dependency in `package.json`. Within that gate it also covers app specs and designs to implement (tabs, stacks, maps, lists, navigation, building from a screenshot), and phrasings like 'implement a mobile app', 'make my app look native', 'add navigation', 'fetch some data', 'upgrade my SDK', 'add Expo to my existing native app', 'ship to the App Store', or 'I'm new to Expo, where do I start'. A fully specified request (SDK pinned, libraries named, layout given) still routes through here — the shared setup rules still apply. Do NOT load it when neither signal is present: a bare React Native project with no `expo` dependency is not Expo work. Detects the real goal, routes to the right expo-* / eas-* skill, and owns the shared setup rules.★ 2.7k GitHub starsSkilliOS App Clip Setupexpo/skills · by expoAdd an iOS App Clip target to an Expo app. Use when the user mentions App Clip, AASA, apple-app-site-association, appclips, smart app banner, or wants to ship a lightweight iOS Clip invoked from a URL alongside their parent app.★ 2.7k GitHub starsSkillApp Store Deploy Agentexpo/skills · by expoBuild and submit iOS and Android apps with EAS to TestFlight, the App Store, or Google Play. Supports Expo and other React Native projects, plus existing native apps. Use for eas.json setup, release pipelines, signing, app versions and build numbers, store submissions, and listing metadata. For Expo websites and API routes, use eas-hosting; for adding React Native screens to a native app, use expo-brownfield.★ 2.7k GitHub starsSkillSleek Mobile App Designersleekdotdesign/agent-skills · by sleekdotdesignUse when the user wants to design a mobile app or UI screens, when they mention their Sleek (sleek.design) projects, or when implementing Sleek designs in code (HTML, React Native, SwiftUI).★ 583 GitHub starsSkillReact Native Animation Builderemilkowalski/skills · by emilkowalskiBuild animations in React Native and Expo, making the decisions in the order that determines whether they feel right — should it animate, which thread it runs on, which properties, spring or timing, how the gesture hands off, how it degrades. Writes the implementation with Reanimated, Gesture Handler, Expo Router and expo-haptics. Use when animating anything in an Expo app, adding gestures, sheets, screen transitions, press feedback or haptics, or fixing motion that stutters on device. For web animation use `animate`.★ 40.8k GitHub starsSkillModern Swift Writing Guideemilkowalski/skills · by emilkowalskiHow to write modern Swift well — modeling with value types, Swift 6 data-race safety and approachable concurrency (@concurrent, main-actor-by-default, actors, task groups), protocols and generics (some vs any), API design, performance and ARC, Swift Testing, macros, and the modern language features agents don't know about yet. Use when writing, reviewing, or migrating Swift, or when a concurrency error, a hang, a data race, a retain cycle, or a performance problem needs fixing.★ 40.8k GitHub stars

More from expo

SkillExpo Task Routerexpo/skills · by expoEntry point and router for every Expo or EAS task. Load this skill first — before writing code and before choosing another expo-* / eas-* skill — when the request, PRD, or spec mentions Expo, EAS, Expo Go, or an expo-* package, or the project has an `expo` dependency in `package.json`. Within that gate it also covers app specs and designs to implement (tabs, stacks, maps, lists, navigation, building from a screenshot), and phrasings like 'implement a mobile app', 'make my app look native', 'add navigation', 'fetch some data', 'upgrade my SDK', 'add Expo to my existing native app', 'ship to the App Store', or 'I'm new to Expo, where do I start'. A fully specified request (SDK pinned, libraries named, layout given) still routes through here — the shared setup rules still apply. Do NOT load it when neither signal is present: a bare React Native project with no `expo` dependency is not Expo work. Detects the real goal, routes to the right expo-* / eas-* skill, and owns the shared setup rules.★ 2.7k GitHub starsSkilliOS App Clip Setupexpo/skills · by expoAdd an iOS App Clip target to an Expo app. Use when the user mentions App Clip, AASA, apple-app-site-association, appclips, smart app banner, or wants to ship a lightweight iOS Clip invoked from a URL alongside their parent app.★ 2.7k GitHub starsSkillApp Store Deploy Agentexpo/skills · by expoBuild and submit iOS and Android apps with EAS to TestFlight, the App Store, or Google Play. Supports Expo and other React Native projects, plus existing native apps. Use for eas.json setup, release pipelines, signing, app versions and build numbers, store submissions, and listing metadata. For Expo websites and API routes, use eas-hosting; for adding React Native screens to a native app, use expo-brownfield.★ 2.7k GitHub starsSkillExpo App Hostingexpo/skills · by expoDeploy Expo websites and Expo Router API routes to EAS Hosting - export the web bundle, run eas deploy for production and PR preview URLs, manage environment secrets and custom domains, and work within the Cloudflare Workers runtime. Also covers authoring API routes (+api.ts handlers, HTTP methods, request handling, CORS). Use when deploying an Expo web app or API routes, setting up EAS Hosting, or configuring hosting environments and domains. Not for native builds or store releases - use the eas-app-stores skill for those.★ 2.7k GitHub starsSkillExpo Performance Observerexpo/skills · by expoUse for anything related to EAS Observe - adding `expo-observe` to an Expo project (AppMetricsRoot/ObserveRoot HOC, markInteractive and ObserveInteractiveMarker, the useObserve hook, the Expo Router / React Navigation integrations for per-route metrics, user-defined events via `Observe.logEvent`, error reporting via ObserveErrorBoundary and `Observe.reportError`, and runtime config such as sampleRate and dispatchInDebug), querying via the EAS CLI (`eas observe:metrics-summary`, `observe:metrics`, `observe:routes`, `observe:events`, `observe:session`, `observe:versions`), interpreting the resulting metrics (cold/warm launch, TTR, TTI, navigation cold/warm TTR, update download, and the TTI frameRate/device/network params for triaging slow startups), or shipping an Observe integration inside a third-party package.★ 2.7k GitHub starsSkillRemote Device Simulatorexpo/skills · by expoRun and control a user's app on a remote iOS/Android simulator hosted on EAS cloud. Read before running any `eas simulator:*` commands - it has the current syntax for this experimental API. Use whenever the user needs a simulator they can't run locally - 'run my app on a cloud simulator', 'use eas simulator to run/install/screenshot my app', 'I'm on Linux/Cursor and need an iOS device', 'no sim on this box / headless CI', 'let an agent click through my app and screenshot it', 'test my dev build on a remote sim with live reload', 'stream a sim to my browser' - even when they don't say 'EAS Simulator' or 'cloud'. On a host WITHOUT a local simulator (Linux, CI, cloud sandbox) it's the default; on macOS, do NOT auto-trigger for a plain 'run on the simulator' - use it only for a cloud/remote/shareable sim, an iOS version they lack, or an agent-driven session. NOT for local sims (expo run:ios, Xcode, Android Studio), EAS Build/Update, web preview, or physical devices.★ 2.7k GitHub stars