expo-router

Par expo · skills

Navigation et routage avec Expo Router. Couvre les routes basées sur les fichiers, les groupes et routes dynamiques, l'organisation des dossiers, Link avec aperçus et menus contextuels, Stack natif, titres de pages, modals et feuilles de formulaire, NativeTabs, en-têtes et barres d'outils, et barres de recherche dans les en-têtes.

npx skills add https://github.com/expo/skills --skill expo-router

Navigation Expo Router

Navigation et routing pour les apps Expo Router. Pour le stylage des écrans, les couleurs, les contrôles, les animations, les médias et les effets visuels, utilisez la skill building-native-ui.

Références

Consultez ces ressources selon vos besoins :

references/
  route-structure.md     Conventions de routes, routes dynamiques, groupes, organisation des dossiers
  tabs.md                NativeTabs, migration depuis les tabs JS, fonctionnalités iOS 26
  toolbar-and-headers.md En-têtes Stack et boutons de barre d'outils, menus, recherche (iOS uniquement)
  form-sheet.md          Form sheets dans expo-router : configuration, pieds de page et interaction de fond.
  search.md              Barre de recherche avec en-têtes, hook useSearch, motifs de filtrage
  zoom-transitions.md    Apple Zoom : transitions zoom fluides avec Link.AppleZoom (iOS 18+)

Style de code

  • Toujours utiliser kebab-case pour les noms de fichiers, ex. comment-card.tsx
  • Toujours supprimer les anciens fichiers de route lors du déplacement ou de la restructuration de la navigation
  • Ne jamais utiliser de caractères spéciaux dans les noms de fichiers
  • Configurer tsconfig.json avec des alias de chemins, et préférer les alias aux imports relatifs pour les refacteurs.

Routes

Voir ./references/route-structure.md pour les conventions de routes détaillées.

  • Les routes appartiennent au répertoire app.
  • Ne jamais co-localiser des composants, types ou utilitaires dans le répertoire app. C'est un anti-pattern.
  • S'assurer que l'app a toujours une route correspondant à "/", elle peut être à l'intérieur d'une route de groupe.

Préférences de bibliothèque

  • Color depuis expo-router pour les couleurs sémantiques natives, pas brut PlatformColor (type-safe, adaptation automatique clair/foncé). Voir building-native-ui pour le motif de palette de couleurs complet.
  • En SDK 56+, ne jamais importer directement depuis @react-navigation/* — utilisez expo-router/react-navigation à la place (couvre @react-navigation/native, /core, /elements, /routers)

Comportement

  • Préférer Stack.SearchBar pour ajouter une barre de recherche à un écran

Navigation

Link

Utilisez <Link href="/path" /> depuis 'expo-router' pour naviguer entre les routes.

import { Link } from 'expo-router';

// Lien basique
<Link href="/path" />

// Envelopper des composants personnalisés
<Link href="/path" asChild>
  <Pressable>...</Pressable>
</Link>

Autant que possible, incluez un <Link.Preview> pour respecter les conventions iOS. Ajoutez des menus contextuels et des aperçus fréquemment pour améliorer la navigation.

Stack

  • TOUJOURS utiliser les fichiers _layout.tsx pour définir les stacks
  • Utiliser Stack depuis 'expo-router/stack' pour les stacks de navigation native

Titre de la page

Définir le titre de la page avec Stack.Title :

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

Menus contextuels

Ajouter des menus contextuels au long press aux composants 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>;

Aperçus de liens

Utilisez les aperçus de liens fréquemment pour améliorer la navigation :

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

L'aperçu de lien peut être utilisé avec des menus contextuels.

Modal

Présenter un écran comme une modale :

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

Préférer ceci à construire un composant modal personnalisé.

Sheet

Présenter un écran comme une form sheet dynamique :

<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>
  • Utiliser contentStyle: { backgroundColor: "transparent" } rend le fond du verre liquide sur iOS 26+.

Structure de route commune

Une mise en page d'app standard avec des tabs et des stacks à l'intérieur de chaque tab :

app/
  _layout.tsx — <NativeTabs />
  (index,search)/
    _layout.tsx — <Stack />
    index.tsx — Liste principale
    search.tsx — Vue de recherche
// 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>
  );
}

Créer une route de groupe partagée afin que les deux tabs puissent pousser les écrans communs :

// 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 },
        headerLargeTitle: true,
        headerBlurEffect: "none",
        headerBackButtonDisplayMode: "minimal",
      }}
    >
      <Stack.Screen name={screen} options={{ title: titles[screen] }} />
      <Stack.Screen name="i/[id]" options={{ headerLargeTitle: false }} />
    </Stack>
  );
}

Skills similaires