expo-native-ui

Par expo · skills

Framework (OSS). Créez de superbes écrans Expo à l'apparence native. Couvre le style Apple HIG, les couleurs sémantiques, les contrôles natifs, les SF Symbols, les médias, les animations, les effets visuels, les dégradés, le stockage et la mise en page responsive. Pour le routage et la navigation, utilisez le skill expo-router.

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

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 :

  1. Commencez par Expo Go : Exécutez npx expo start et scannez le code QR avec Expo Go
  2. Vérifiez si les fonctionnalités fonctionnent : Testez votre app complètement dans Expo Go
  3. 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-audio et non expo-av
  • expo-video et non expo-av
  • expo-image avec source="sf:name" pour SF Symbols, et non expo-symbols ou @expo/vector-icons
  • react-native-safe-area-context et non react-native SafeAreaView
  • process.env.EXPO_OS et non Platform.OS
  • React.use et non React.useContext
  • Composant expo-image Image au lieu de l'élément intrinsèque img
  • expo-glass-effect pour les arrière-plans liquid glass
  • Color de expo-router pour les couleurs sémantiques natives, et non PlatformColor brut (type-safe, s'adapte automatiquement en clair/sombre)
  • Dans SDK 56+, n'importez jamais directement de @react-navigation/* — utilisez expo-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 contentContainerStyle au 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 / PlatformColor dans les styles Reanimated — utilisez des couleurs statiques là-bas (voir references/animations.md).
  • Platform.select({...})! retourne string | OpaqueColorValue. La plupart des props de style React Native acceptent ColorValue (string | OpaqueColorValue) donc cela fonctionne bien. Mais certaines props tierces n'acceptent que string (par ex. tintColor sur expo-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.

Skills similaires