Expo Router

作者 expocd752143d19eMIT2.6K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫昨天更新

Framework (OSS). 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.

AI 產生的概覽

為 Expo Router 應用程式提供導覽與路由實作指引,涵蓋路由、連結、堆疊、分頁、頁首與表單頁。

功能
此技能提供在 Expo Router 應用程式中實作導覽與路由的參考說明。內容涵蓋以檔案為基礎的路由、群組與動態路由、目錄組織、帶預覽與情境選單的 Link 元件、原生 Stack 佈局、頁面標題、模態與表單頁、NativeTabs、頁首與工具列,以及頁首搜尋列。它也說明程式碼風格與函式庫使用偏好,例如檔名使用 kebab-case,以及使用 expo-router 匯出而非直接從 @react-navigation 匯入。它產出的是指引與程式碼模式,而非可執行的指令碼。
適用情境
當你在開發 Expo Router 應用程式,且需要建立或重整導覽、路由、分頁、堆疊、頁首、模態、表單頁或搜尋列時使用。它也適用於決定如何組織路由檔案,或應優先採用哪些導覽 API 與匯入方式。
執行需求
不包含指令碼,僅為說明與參考文件。它假定存在使用 React Native 與 TypeScript 的 Expo Router 專案,並提到可選的樣式與動畫相關技能。回饋部分提到一個 npx 指令,但執行它並非使用此技能指引所必需。

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

Link

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

tsx
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:

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

Context Menus

Add long press context menus to Link components:

tsx
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>;

Link Previews

Use link previews frequently to enhance navigation:

tsx
<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:

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

Prefer this to building a custom modal component.

Sheet

Present a screen as a dynamic form sheet:

tsx
<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
tsx
// app/_layout.tsximport { 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:

tsx
// app/(index,search)/_layout.tsximport { 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:

bash
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.

來源與署名

來源:expo/skills位於plugins/expo/skills/expo-router提交cd75214

授權條款: MIT

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架