Directives pour l'interface native Expo
Pour les routes, les liens, les stacks, les tabs, les modales, les sheets et les headers, utilisez la skill expo-router.
Références
Consultez ces ressources au besoin :
references/
animations.md Reanimated : entrée, sortie, layout, scroll-driven, gestes
controls.md iOS natif : Switch, Slider, SegmentedControl, DateTimePicker, Picker
gradients.md Gradients CSS via experimental_backgroundImage (New Arch uniquement)
icons.md SF Symbols via expo-image (sf: source), noms, animations, poids
media.md Caméra, audio, vidéo et sauvegarde de fichiers
storage.md SQLite, AsyncStorage, SecureStore
visual-effects.md Blur (expo-blur) et liquid glass (expo-glass-effect)
webgpu-three.md Graphiques 3D, jeux, visualisations GPU avec WebGPU et Three.js
Exécution de l'application
CRITIQUE : Essayez toujours Expo Go en premier avant de créer des builds personnalisées.
La plupart des apps Expo fonctionnent dans Expo Go sans aucun code natif personnalisé. Avant d'exécuter npx expo run:ios ou npx expo run:android :
- Commencez par Expo Go : Exécutez
npx expo startet scannez le code QR avec Expo Go - Vérifiez si les fonctionnalités fonctionnent : Testez votre app complètement dans Expo Go
- Créez des builds personnalisées seulement si nécessaire — voir ci-dessous
Quand les builds personnalisés sont nécessaires
Vous avez besoin de npx expo run:ios/android ou eas build SEULEMENT en cas d'utilisation de :
- Modules Expo locaux (code natif personnalisé dans
modules/) - Cibles Apple (widgets, app clips, extensions via
@bacons/apple-targets) - Modules natifs tiers non inclus dans Expo Go
- Configuration native personnalisée qui ne peut pas être exprimée dans
app.json
Quand Expo Go fonctionne
Expo Go supporte une énorme gamme de fonctionnalités dès le départ :
- Tous les packages
expo-*(caméra, localisation, notifications, etc.) - Navigation Expo Router
- La plupart des bibliothèques d'interface (reanimated, gesture handler, etc.)
- Notifications push, deep links, et plus
Si vous n'êtes pas sûr, essayez Expo Go en premier. La création de builds personnalisés ajoute de la complexité, ralentit l'itération et nécessite la configuration de Xcode/Android Studio.
Style de code
- Soyez prudent avec les chaînes non terminées. Assurez-vous que les backticks imbriquées sont échappés ; n'oubliez jamais d'échapper correctement les guillemets.
- Utilisez toujours les instructions import en haut du fichier.
- Utilisez toujours le kebab-case pour les noms de fichiers, par exemple
comment-card.tsx - Ne jamais utiliser de caractères spéciaux dans les noms de fichiers
- Configurez tsconfig.json avec des alias de chemin, et préférez les alias aux imports relatifs pour les refactorisations.
Préférences de bibliothèques
- Ne jamais utiliser de modules supprimés de React Native tels que Picker, WebView, SafeAreaView ou AsyncStorage
- Ne jamais utiliser l'ancien expo-permissions
expo-audioet nonexpo-avexpo-videoet nonexpo-avexpo-imageavecsource="sf:name"pour SF Symbols, et nonexpo-symbolsou@expo/vector-iconsreact-native-safe-area-contextet non react-native SafeAreaViewprocess.env.EXPO_OSet nonPlatform.OSReact.useet nonReact.useContext- Composant
expo-imageImage au lieu de l'élément intrinsèqueimg expo-glass-effectpour les arrière-plans liquid glassColordeexpo-routerpour les couleurs sémantiques natives, et nonPlatformColorbrut (type-safe, s'adapte automatiquement en clair/sombre)- Dans SDK 56+, n'importez jamais directement de
@react-navigation/*— utilisezexpo-router/react-navigationà la place (couvre@react-navigation/native,/core,/elements,/routers)
Responsivité
- Enveloppez toujours le composant racine dans une scroll view pour la responsivité
- Utilisez
<ScrollView contentInsetAdjustmentBehavior="automatic" />au lieu de<SafeAreaView>pour des insets de zone sécurisée plus intelligents contentInsetAdjustmentBehavior="automatic"doit également être appliqué à FlatList et SectionList- Utilisez flexbox au lieu de l'API Dimensions
- PRÉFÉREZ TOUJOURS
useWindowDimensionsàDimensions.get()pour mesurer la taille de l'écran
Comportement
- Utilisez expo-haptics de manière conditionnelle sur iOS pour créer des expériences plus agréables
- Utilisez des vues avec haptics intégrées comme
<Switch />de React Native et@react-native-community/datetimepicker - Quand une route appartient à un Stack, son premier enfant devrait presque toujours être une ScrollView avec
contentInsetAdjustmentBehavior="automatic"défini - Quand vous ajoutez une
ScrollViewà la page, elle devrait presque toujours être le premier composant à l'intérieur du composant de route - Utilisez la prop
<Text selectable />sur du texte contenant des données qui pourraient être copiées - Envisagez de formater les grands nombres comme 1,4M ou 38k
- Ne jamais utiliser d'éléments intrinsèques comme 'img' ou 'div' sauf dans une webview ou un composant Expo DOM
Style
Suivez les directives d'interface humaine d'Apple.
Règles générales de style
- Préférez flex gap à margin et padding
- Préférez padding à margin si possible
- Tenez toujours compte de la zone sécurisée, soit avec des headers de stack, des tabs, ou
contentInsetAdjustmentBehavior="automatic"sur ScrollView/FlatList - Assurez-vous que les insets de zone sécurisée supérieur et inférieur sont tous deux pris en compte
- Styles inline plutôt que StyleSheet.create sauf si la réutilisation de styles est plus rapide
- Ajoutez des animations d'entrée et de sortie pour les changements d'état
- Utilisez
{ borderCurve: 'continuous' }pour les coins arrondis sauf si vous créez une forme de capsule - UTILISEZ TOUJOURS un titre de stack de navigation au lieu d'un élément texte personnalisé sur la page
- Quand vous paddez une ScrollView, utilisez le padding et gap
contentContainerStyleau lieu du padding sur la ScrollView elle-même (réduit le clipping) - CSS et Tailwind ne sont pas supportés — utilisez les styles inline
Couleurs
Utilisez l'API Color de expo-router pour les couleurs sémantiques natives. C'est un wrapper type-safe sur PlatformColor qui expose les couleurs UIKit iOS via Color.ios.* et les couleurs Material 3 Android via Color.android.material.* (static) ou Color.android.dynamic.* (s'adapte au fond d'écran de l'utilisateur sur Android 12+). Celles-ci se résolvent sur l'appareil et s'adaptent automatiquement au mode clair/sombre et aux paramètres d'accessibilité, vous n'avez donc plus besoin de maintenir des tables hex claires/sombres séparées ou un fichier colors.web.ts.
Color est spécifique à la plateforme, enveloppez donc chaque valeur dans Platform.select avec un fallback hex default pour le web. Centralisez la palette dans theme/colors.ts et importez colors partout :
// theme/colors.ts
import { Platform } from "react-native";
import { Color } from "expo-router";
export const colors = {
label: Platform.select({
ios: Color.ios.label,
android: Color.android.dynamic.onSurface,
default: "#000000",
})!,
secondaryLabel: Platform.select({
ios: Color.ios.secondaryLabel,
android: Color.android.dynamic.onSurfaceVariant,
default: "#3c3c43",
})!,
separator: Platform.select({
ios: Color.ios.separator,
android: Color.android.dynamic.outlineVariant,
default: "#c6c6c8",
})!,
systemBackground: Platform.select({
ios: Color.ios.systemBackground,
android: Color.android.dynamic.surface,
default: "#ffffff",
})!,
systemBlue: Platform.select({
ios: Color.ios.systemBlue,
android: Color.android.dynamic.primary,
default: "#007aff",
})!,
};
import { colors } from "@/theme/colors";
<View style={{ backgroundColor: colors.systemBackground }}>
<Text style={{ color: colors.label }}>Title</Text>
</View>;
- iOS ré-résout ces couleurs automatiquement quand le thème système change. Sur Android, appelez
useColorScheme()à l'intérieur de tout composant qui les rend pour qu'il se re-render quand le thème bascule (nécessaire quand React Compiler mémorise le composant). - Ne passez pas de valeurs
Color/PlatformColordans les styles Reanimated — utilisez des couleurs statiques là-bas (voirreferences/animations.md). Platform.select({...})!retournestring | OpaqueColorValue. La plupart des props de style React Native acceptentColorValue(string | OpaqueColorValue) donc cela fonctionne bien. Mais certaines props tierces n'acceptent questring(par ex.tintColorsurexpo-image). Convertissez si nécessaire :colors.label as string.
Style de texte
- Ajoutez la prop
selectableà chaque élément<Text/>affichant des données importantes ou des messages d'erreur - Les compteurs doivent utiliser
{ fontVariant: 'tabular-nums' }pour l'alignement
Ombres
Utilisez la prop de style CSS boxShadow. N'utilisez JAMAIS les styles d'ombre ou d'élévation legacy de React Native.
<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />
Les ombres 'inset' sont supportées.