← Expo2CONTENT HISTORY

Update to Expo2

Snapshot Nov 6, 2026 · 18:22 UTC · version 1.14.6

Collection source: downloaded plugin package.

WHAT CHANGED

First saved snapshot

No earlier snapshot is available to establish a change.

Save Expo2 and check future changes in Following.

Up to 3 plugins free · no card required.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill; for motion and animation, use the expo-animation skill.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 408
    },
    {
      "relative_path": "references/controls.md",
      "size_in_bytes": 5018
    },
    {
      "relative_path": "references/gradients.md",
      "size_in_bytes": 2717
    },
    {
      "relative_path": "references/icons.md",
      "size_in_bytes": 5849
    },
    {
      "relative_path": "references/media.md",
      "size_in_bytes": 6229
    },
    {
      "relative_path": "references/storage.md",
      "size_in_bytes": 2935
    },
    {
      "relative_path": "references/visual-effects.md",
      "size_in_bytes": 5201
    },
    {
      "relative_path": "references/webgpu-three.md",
      "size_in_bytes": 14466
    }
  ],
  "name": "expo-native-ui",
  "skill_md_contents": "---\nname: expo-native-ui\ndescription: Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill; for motion and animation, use the expo-animation skill.\nlicense: MIT\n---\n\n# Expo Native UI Guidelines\n\nFor routes, links, stacks, tabs, modals, sheets, and headers, use the `expo-router` skill. For any motion — entering/exiting, gestures, springs, keyboard-driven UI — use the `expo-animation` skill.\n\n> **Before picking any UI component, check `expo-ui` first.** `@expo/ui` provides native equivalents — BottomSheet, Button, Picker, Slider, Menu, Section, Switch, SegmentedControl, and more — rendered as real SwiftUI on iOS and Jetpack Compose on Android, available in Expo Go on SDK 56+ with no custom build. Load the **`expo-ui`** skill to find the right component before falling back to React Native built-ins or community libraries. This skill (`expo-native-ui`) covers the surrounding structure: Expo Router navigation, layout, styling, and visual effects.\n\n## References\n\nConsult these resources as needed:\n\n```\nreferences/\n  controls.md            Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker\n  gradients.md           CSS gradients via experimental_backgroundImage (New Arch only)\n  icons.md               SF Symbols via expo-symbols SymbolView: names, weights, animations; Material icons on Android\n  media.md               Camera, audio, video, and file saving\n  storage.md             SQLite, AsyncStorage, SecureStore\n  visual-effects.md      Blur (expo-blur) and liquid glass (expo-glass-effect)\n  webgpu-three.md        3D graphics, games, GPU visualizations with WebGPU and Three.js\n```\n\n## Running the App\n\n**CRITICAL: Always try Expo Go first before creating custom builds.**\n\nMost Expo apps work in Expo Go without any custom native code. Before running `npx expo run:ios` or `npx expo run:android`:\n\n1. **Start with Expo Go**: Run `npx expo start` and scan the QR code with Expo Go\n2. **Check if features work**: Test your app thoroughly in Expo Go\n3. **Only create custom builds when required** - see below\n\n### When Custom Builds Are Required\n\nYou need `npx expo run:ios/android` or `npx --yes eas-cli@27.4.1 build` ONLY when using:\n\n- **Local Expo modules** (custom native code in `modules/`)\n- **Apple targets** (widgets, app clips, extensions via `@bacons/apple-targets`)\n- **Third-party native modules** not included in Expo Go\n- **Custom native configuration** that can't be expressed in `app.json`\n\n### When Expo Go Works\n\nExpo Go supports a wide range of features out of the box:\n\n- Most `expo-*` packages (camera, location, sensors, sqlite, etc.) — but not all: remote push notifications don't work in Expo Go on Android since SDK 53, and some packages need native capabilities Expo Go doesn't bundle (e.g. WebGPU — see `references/webgpu-three.md`)\n- Expo Router navigation and deep links\n- Most UI libraries (reanimated, gesture handler, etc.)\n\n**If you're unsure, try Expo Go first.** Creating custom builds adds complexity, slower iteration, and requires Xcode/Android Studio setup.\n\n## Code Style\n\n- Be cautious of unterminated strings. Ensure nested backticks are escaped; never forget to escape quotes correctly.\n- Always use import statements at the top of the file.\n- Always use kebab-case for file names, e.g. `comment-card.tsx`\n- Never use special characters in file names\n- Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.\n\n## Library Preferences\n\n- **For any sheet, picker, slider, toggle, menu, or grouped-form section: use `@expo/ui` (see `expo-ui` skill) before reaching for a React Native built-in or community library** — it renders native SwiftUI/Compose and works in Expo Go on SDK 56+. For grouped/settings-style rows (short, fixed-length), use `@expo/ui`'s `List` + `ListItem`. For large or unknown-length scrolling lists (feeds, search results, catalogs), use `FlatList` or `FlashList` — `@expo/ui`'s `List` is not virtualized.\n- Never use modules removed from React Native such as Picker, WebView, SafeAreaView, or AsyncStorage\n- Never use legacy expo-permissions\n- `expo-audio` not `expo-av`\n- `expo-video` not `expo-av`\n- `expo-symbols` (`SymbolView`) for SF Symbols on iOS, not `@expo/vector-icons` — see `references/icons.md`. SF Symbols are Apple-only: on Android every icon needs a Material source (`md` prop on NativeTabs triggers; in-screen options under \"Android: Material Icons\" in icons.md), never SF-only iconography\n- `react-native-safe-area-context` not react-native SafeAreaView\n- `process.env.EXPO_OS` not `Platform.OS`\n- `React.use` not `React.useContext`\n- `expo-image` Image component instead of intrinsic element `img`\n- `expo-glass-effect` for liquid glass backdrops\n- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark)\n- In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`)\n\n## Responsiveness\n\n- Wrap screens with scrollable content in a ScrollView. Screens whose root is a FlatList/FlashList must not add an outer ScrollView (the list is the scroll container), and full-bleed screens (camera, map, canvas) need neither\n- Use `<ScrollView contentInsetAdjustmentBehavior=\"automatic\" />` instead of `<SafeAreaView>` for smarter safe area insets\n- `contentInsetAdjustmentBehavior=\"automatic\"` should be applied to FlatList and SectionList as well\n- Use flexbox instead of Dimensions API\n- ALWAYS prefer `useWindowDimensions` over `Dimensions.get()` to measure screen size\n\n## Behavior\n\n- Use expo-haptics conditionally on iOS to make more delightful experiences\n- Use views with built-in haptics like `<Switch />` from React Native and `@react-native-community/datetimepicker`\n- When a Stack route has scrollable content, make the ScrollView (or FlatList) the first component inside the route, with `contentInsetAdjustmentBehavior=\"automatic\"` set\n- Use the `<Text selectable />` prop on text containing data that could be copied\n- Consider formatting large numbers like 1.4M or 38k\n- Never use intrinsic elements like 'img' or 'div' unless in a webview or Expo DOM component\n- Every screen that loads data has four states (loading, error, empty, content) - never show the empty state while the first load is still resolving; the rules live in the `expo-data-fetching` skill\n- On scrollable forms and search results, use `keyboardShouldPersistTaps=\"handled\"` so controls receive the first tap and unhandled taps can dismiss the keyboard. Use `\"always\"` only when unhandled taps should also keep it open\n- A form's primary action must never sit under the keyboard. For UI that tracks the keyboard's real frame, load the `expo-animation` skill's keyboard recipe (`react-native-keyboard-controller`) - never `Keyboard.addListener` plus a timing animation\n- Every enabled control must perform its advertised action: search filters results, Save commits edits, and settings affect behavior. Empty handlers and success alerts are not implementations; local state is enough when the user requested a prototype\n- For async saves, preserve drafts and handle pending/failure states per `expo-data-fetching`; do not dismiss a form before its save succeeds\n\nBefore calling a screen complete, walk through its primary task, including one failure and recovery when it loads or saves data. Check keyboard access and back/dismiss behavior. Try long titles, missing images, no search results, and large system text; required actions must remain reachable. Report what you exercised and what you could not run.\n\n# Styling\n\nFollow each platform's own design language: Apple Human Interface Guidelines on iOS, Material Design 3 on Android. Never dress one platform in the other's uniform - no FAB or ripple in iOS layouts; no hand-built iOS chrome (back-chevrons, large-title text, iOS-styled switches) on Android.\n\n## General Styling Rules\n\n- Prefer flex gap over margin and padding styles\n- Prefer padding over margin where possible\n- Always account for safe area, either with stack headers, tabs, or ScrollView/FlatList `contentInsetAdjustmentBehavior=\"automatic\"`\n- Ensure both top and bottom safe area insets are accounted for\n- Inline styles not StyleSheet.create unless reusing styles is faster\n- For any motion or animation work, load the `expo-animation` skill — it owns the animate-or-not decision, timing values, and interruption rules\n- Use `{ borderCurve: 'continuous' }` for rounded corners unless creating a capsule shape\n- ALWAYS use a navigation stack title instead of a custom text element on the page\n- When padding a ScrollView, use `contentContainerStyle` padding and gap instead of padding on the ScrollView itself (reduces clipping)\n- CSS and Tailwind are not supported - use inline styles\n\n## Colors\n\nUse the `Color` API from `expo-router` for native semantic colors. It is a type-safe wrapper over `PlatformColor` that exposes iOS UIKit colors through `Color.ios.*` and Android Material 3 colors through `Color.android.material.*` (static) or `Color.android.dynamic.*` (adapts to the user's wallpaper on Android 12+). These resolve on-device and automatically adapt to light/dark mode and accessibility settings, so you no longer maintain separate light/dark hex tables or a `colors.web.ts` file.\n\n`Color` is platform-specific, so wrap each value in `Platform.select` with a `default` hex fallback for web. Centralize the palette in `theme/colors.ts` and import `colors` everywhere:\n\n```tsx\n// theme/colors.ts\nimport { Platform } from \"react-native\";\nimport { Color } from \"expo-router\";\n\nexport const colors = {\n  label: Platform.select({\n    ios: Color.ios.label,\n    android: Color.android.dynamic.onSurface,\n    default: \"#000000\",\n  })!,\n  secondaryLabel: Platform.select({\n    ios: Color.ios.secondaryLabel,\n    android: Color.android.dynamic.onSurfaceVariant,\n    default: \"#3c3c43\",\n  })!,\n  separator: Platform.select({\n    ios: Color.ios.separator,\n    android: Color.android.dynamic.outlineVariant,\n    default: \"#c6c6c8\",\n  })!,\n  systemBackground: Platform.select({\n    ios: Color.ios.systemBackground,\n    android: Color.android.dynamic.surface,\n    default: \"#ffffff\",\n  })!,\n  secondarySystemBackground: Platform.select({\n    ios: Color.ios.secondarySystemBackground,\n    android: Color.android.dynamic.surfaceVariant,\n    default: \"#f2f2f7\",\n  })!,\n  systemBlue: Platform.select({\n    ios: Color.ios.systemBlue,\n    android: Color.android.dynamic.primary,\n    default: \"#007aff\",\n  })!,\n};\n```\n\n```tsx\nimport { colors } from \"@/theme/colors\";\n\n<View style={{ backgroundColor: colors.systemBackground }}>\n  <Text style={{ color: colors.label }}>Title</Text>\n</View>;\n```\n\n- iOS re-resolves these colors automatically when the system theme changes. On Android, call `useColorScheme()` inside any component that renders them so it re-renders when the theme flips (required when React Compiler memoizes the component).\n- Don't pass `Color` / `PlatformColor` values into Reanimated styles — they are opaque native color objects, not strings; use static colors there.\n- `Platform.select({...})!` returns `string | OpaqueColorValue`. Most React Native style props accept `ColorValue` (`string | OpaqueColorValue`) so this works fine. But some third-party props only accept `string` (e.g. `tintColor` on `expo-image`). Cast when needed: `colors.label as string`.\n\n## Text Styling\n\n- Add the `selectable` prop to every `<Text/>` element displaying important data or error messages\n- Counters should use `{ fontVariant: 'tabular-nums' }` for alignment\n\n## Shadows\n\nUse CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevation styles.\n\n```tsx\n<View style={{ boxShadow: \"0 1px 2px rgba(0, 0, 0, 0.05)\" }} />\n```\n\n'inset' shadows are supported.\n\n## Submitting Feedback\nWhen the user requests feedback submission, use:\n```bash\nnpx --yes @expo/agent-cli@1.0.23 feedback --category skills --subject \"expo-native-ui\" \"<actionable feedback>\"\n```\nInclude only relevant technical details; keep credentials, private data, and conversation contents out of feedback.\n"
}

SHA-256 of public snapshot: 80755becb2e66ad0c4c7b272a7946e086d0bba236fd5dfdc922b7c19d2def4ea