expo-router について
expo-router は、Expo Router アプリを開発する人向けのナビゲーションスキルです。ルート構成に加え、スタック、タブ、リンク、モーダル、シートなどのネイティブなナビゲーションパターンを解説します。
主な機能
- 01ルート構成の規約
- 02スタックとタブのナビゲーション指針
- 03リンクと階層ナビゲーションのパターン
- 04モーダルとフォームシートの指針
- 05ヘッダーと検索のパターン
活用シーン
- 01Expo アプリのルート整理
- 02スタックまたはタブナビゲーションの構築
- 03画面をモーダルやシートとして表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ expo/ skills --skill expo-routerインストール後、Claude Code で/expo-routerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/form-sheet.mdroute-structure.mdsearch.mdtabs.mdtoolbar-and-headers.mdzoom-transitions.md詳細
Expo Router ナビゲーション
Expo Router アプリのナビゲーションとルーティングです。画面のスタイリング、色、コントロール、メディア、視覚効果には expo-native-ui スキルを、モーションとジェスチャーには expo-animation を使用してください。
リファレンス
必要に応じて、以下のリソースを参照してください。
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+)
コードスタイル
- ファイル名には常にケバブケースを使用してください。例:
comment-card.tsx - ナビゲーションを移動または再構成するときは、古いルートファイルを必ず削除してください
- ファイル名に特殊文字は使用しないでください
- tsconfig.json でパスエイリアスを設定し、リファクタリングでは相対インポートよりエイリアスを優先してください。
ルート
ルートの規約について詳しくは、./references/route-structure.md を参照してください。
- ルートは
appディレクトリに配置してください。 - コンポーネント、型、ユーティリティを app ディレクトリに置かないでください。これはアンチパターンです。
- アプリには必ず「/」に一致するルートを用意してください。グループルート内に配置してもかまいません。
ライブラリの優先事項
- ネイティブのセマンティックカラーには、
PlatformColorを直接使わずexpo-routerのColorを使用してください(型安全で、ライト/ダークモードに自動対応します)。カラーパレットのパターン全体についてはexpo-native-uiを参照してください。 - SDK 56 以降では、
@react-navigation/*から直接インポートしないでください。代わりにexpo-router/react-navigationを使用してください(@react-navigation/native、/core、/elements、/routersをカバーしています)。
動作
- 画面に検索バーを追加するには、
Stack.SearchBarを優先してください
ナビゲーション
リンク
ルート間のナビゲーションには、'expo-router' の <Link href="/path" /> を使用してください。
import { Link } from 'expo-router';
// Basic link
<Link href="/path" />
// Wrapping custom components
<Link href="/path" asChild>
<Pressable>...</Pressable>
</Link>
可能な限り <Link.Preview> を含めて、iOS の規約に準拠してください。ナビゲーションをより充実させるため、コンテキストメニューとプレビューを頻繁に追加してください。
Stack
- スタックの定義には、必ず
_layout.tsxファイルを使用してください - ネイティブのナビゲーションスタックには、'expo-router/stack' の Stack を使用してください
ページタイトル
Stack.Title でページタイトルを設定します。
<Stack.Title>Home</Stack.Title>
コンテキストメニュー
Link コンポーネントに長押しのコンテキストメニューを追加します。
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 href="/settings">
<Link.Trigger>
<Pressable>
<Card />
</Pressable>
</Link.Trigger>
<Link.Preview />
</Link>
リンクプレビューはコンテキストメニューと併用できます。
モーダル
画面をモーダルとして表示します。
<Stack.Screen name="modal" options={{ presentation: "modal" }} />
カスタムモーダルコンポーネントを作成するよりも、こちらを優先してください。
シート
画面を動的なフォームシートとして表示します。
<Stack.Screen
name="sheet"
options={{
presentation: "formSheet",
sheetGrabberVisible: true,
sheetAllowedDetents: [0.5, 1.0],
contentStyle: { backgroundColor: "transparent" },
}}
/>
contentStyle: { backgroundColor: "transparent" }を使用すると、iOS 26 以降で背景がリキッドグラスになります。
一般的なルート構造
各タブ内にタブとスタックを配置した標準的なアプリレイアウトです。
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>
);
}
両方のタブから共通の画面に遷移できるように、共有グループルートを作成します。
// 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 は SDK 56 以降のオプション名です。古い SDK では headerLargeTitle を使用しますが、上流では非推奨になっています。
フィードバックの送信
このスキルにエラー、誤解を招く情報、または古い情報がある場合は、Expo が改善できるよう報告してください。
npx --yes @expo/agent-cli@latest feedback --category skills --subject "expo-router" "<actionable feedback>"
具体的で実行可能な内容がある場合にのみ送信してください。関連するコンテキストをできるだけ詳しく記載してください。
エージェントが Expo のタスクを繰り返し失敗する場合や、ユーザーが介入しなければならない場合は、タスクの概要、期待される結果、問題の内容を簡潔に報告し、--category evals と、関連する Expo のパッケージまたはコマンドを --subject として指定してください。