expo-sdk
Original:🇺🇸 English
Translated
Expo SDK 54+ platform patterns. Use when configuring Expo apps, setting up root layouts, using expo-image, expo-haptics, safe areas, bottom sheets, FlashList, or StatusBar.
1installs
Sourcenguyenhuuca/assessment
Added on
NPX Install
npx skill4agent add nguyenhuuca/assessment expo-sdkTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Expo SDK
Overview
Expo SDK 54+ provides a managed React Native development environment with file-based routing (Expo Router), native module access, and streamlined build tooling. This skill covers app configuration, the root layout provider pattern, and key Expo/RN libraries.
Prerequisite: or Expo SDK 54+ in
npx create-expo-apppackage.jsonWorkflows
Setting up a new Expo demo:
- Create project:
npx create-expo-app [demo-name] --template blank-typescript - Install core dependencies:
pnpm add expo-router expo-image expo-haptics react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet @shopify/flash-list lucide-react-native nativewind tailwindcss@3 - Configure NativeWind (see skill)
nativewind - Set up root layout with provider stack
- Configure with scheme, name, splash
app.json - Add route groups and screens
- Run: (Expo dev server)
pnpm start
Adding a new library:
- Install with pnpm:
pnpm add [library] - Check if Expo config plugin needed in
app.json - Rebuild dev client if native module added:
npx expo prebuild
Guidance
app.json Configuration
Key fields for demo apps:
| Field | Purpose |
|---|---|
| Display name |
| URL-safe identifier |
| Deep link scheme (e.g., |
| |
| Splash screen configuration |
| iOS bundle ID |
| Android package name |
| Expo config plugins (e.g., |
Root Layout Provider Pattern
The root wraps the entire app with providers. Standard order:
app/_layout.tsxGestureHandlerRootView (flex: 1)
└── SafeAreaProvider
└── ThemeProvider / Context
└── Stack (Expo Router)- must be outermost (required by gesture handler and bottom sheets)
GestureHandlerRootView - provides safe area insets to all descendants
SafeAreaProvider - App-level context providers go between SafeAreaProvider and Stack
- for custom headers
<Stack screenOptions={{ headerShown: false }} />
expo-image (replaces RN Image)
Use for all image rendering — provides caching, blurhash placeholders, content-fit modes, and animated transitions.
expo-imageKey props:
- — URI string or require() for local images
source - — blurhash string for loading state
placeholder - —
contentFit|'cover'|'contain''fill' - — fade-in duration in ms (e.g.,
transition)300
expo-haptics
Provide tactile feedback on interactions:
- — light tap for selections, toggles
Haptics.selectionAsync() - — button press, card tap
Haptics.impactAsync(ImpactFeedbackStyle.Medium) - — action completion
Haptics.notificationAsync(NotificationFeedbackType.Success)
Use sparingly — haptics on every touch is annoying.
Safe Area Insets
Account for device notch, status bar, and home indicator:
- — returns
useSafeAreaInsets()in points{ top, bottom, left, right } - Apply to screen containers:
paddingTop: insets.top - NativeWind classes: use or wrap in SafeAreaView
pt-[${insets.top}px]
@gorhom/bottom-sheet
Replaces Radix Dialog for mobile modal patterns:
- Use for detail views, selections, filters, forms
- Define snap points:
snapPoints={['25%', '50%', '90%']} - Backdrop: with press-to-dismiss
backdropComponent - for scrollable content inside sheets
BottomSheetScrollView - Requires as ancestor
GestureHandlerRootView
FlashList (replaces FlatList)
High-performance list rendering from :
@shopify/flash-list- Drop-in FlatList replacement with mandatory prop
estimatedItemSize - — estimated height of each item in points
estimatedItemSize={80} - Recycling architecture for smooth 60fps scrolling
- Use for NativeWind styling
contentContainerClassName
lucide-react-native
Icon library for React Native (matches web lucide-react):
- Import individual icons:
import { Home, Settings, ChevronRight } from 'lucide-react-native' - Props: ,
size,colorstrokeWidth - Consistent icon set across mobile and web codebases
StatusBar
Configure status bar appearance per screen:
- for light backgrounds
<StatusBar style="dark" /> - for dark backgrounds
<StatusBar style="light" /> - Import from
expo-status-bar
Best Practices
- Wrap root layout in with
GestureHandlerRootViewstyle={{ flex: 1 }} - Use expo-image for all images (caching, blurhash, performance)
- Add haptics to primary actions only (buttons, major selections) — not every touch
- Set on all FlashList components
estimatedItemSize - Place providers in root , not in individual screens
_layout.tsx - Use for manual padding,
useSafeAreaInsets()for simple wrappingSafeAreaView - Test on real device for haptics and performance verification
Anti-Patterns
- Using React Native instead of
Imageexpo-image - Using for large datasets instead of
FlatListFlashList - Forgetting (causes bottom sheet and gesture crashes)
GestureHandlerRootView - Overusing haptics on every interaction
- Hardcoding status bar height instead of using safe area insets
- Missing on FlashList (required prop, console warning)
estimatedItemSize - Placing inside ScrollView (causes layout issues)
SafeAreaView - Not including plugin in
expo-routerplugins arrayapp.json