Native UI with Expo Router
Patterns and conventions for building native mobile applications with Expo Router and React Native.
References
Consult these as needed:
- ./references/route-structure.md — Route conventions, dynamic routes, groups, folder organization INLINECODE1 — Native tab bar with NativeTabs, iOS 26 features INLINECODE2 — SF Symbols with expo-symbols, icon names, animations, weights INLINECODE3 — Native iOS controls: Switch, Slider, SegmentedControl, DateTimePicker INLINECODE4 — Blur effects (expo-blur) and liquid glass (expo-glass-effect) INLINECODE5 — Reanimated: entering, exiting, layout, scroll-driven, gestures INLINECODE6 — Search bar with headers, useSearch hook, filtering patterns INLINECODE7 — CSS gradients via experimental_backgroundImage (New Architecture only) INLINECODE8 — Camera, audio, video, file saving INLINECODE9 — SQLite, AsyncStorage, SecureStore INLINECODE10 — 3D graphics and GPU visualizations with WebGPU/Three.js INLINECODE11 — Stack headers and toolbar with buttons, menus, search bars (iOS) INLINECODE12 — Form sheet presentation patterns
Running the App
Always try Expo Go first before creating custom builds.
1. Start with npx expo start and scan the QR code Test features in Expo Go Only create custom builds when required
When Custom Builds Are Required
Use npx expo run:ios/android or eas build only for:
- Local Expo modules (custom native code in modules/) Apple targets (widgets, app clips via @bacons/apple-targets) Third-party native modules not in Expo Go Custom native configuration beyond INLINECODE18
Expo Go supports all expo-* packages, Expo Router, Reanimated, Gesture Handler, push notifications, and deep links out of the box.
Installation
OpenClaw / Moltbot / Clawbot
CODEBLOCK0
Code Style
- Escape nested backticks and quotes correctly Always use import statements at the top of the file Use kebab-case for file names: INLINECODE20 Remove old route files when restructuring navigation No special characters in file names Configure tsconfig.json path aliases; prefer aliases over relative imports
Routes
See ./references/route-structure.md for detailed conventions.
- Routes belong in the app directory Never co-locate components, types, or utilities in app/ — this is an anti-pattern Always have a route matching /, possibly inside a group route
Library Preferences
Use Instead of INLINECODE26 INLINECODE27 INLINECODE28
expo-av |
|
expo-symbols |
@expo/vector-icons |
|
react-native-safe-area-context | RN SafeAreaView |
|
process.env.EXPO_OS |
Platform.OS |
|
React.use |
React.useContext |
|
expo-image | Intrinsic
img element |
|
expo-glass-effect | Custom glass backdrops |
Never use deprecated modules: Picker, WebView, SafeAreaView, AsyncStorage (from RN core), or legacy expo-permissions.
Responsiveness
- Wrap root components in a scroll view Use <ScrollView contentInsetAdjustmentBehavior="automatic" /> instead of INLINECODE42 Apply contentInsetAdjustmentBehavior="automatic" to FlatList and SectionList too Use flexbox instead of Dimensions API Prefer useWindowDimensions over Dimensions.get() for screen measurement
Behavior
- Use expo-haptics conditionally on iOS for delightful interactions Use views with built-in haptics (<Switch />, @react-native-community/datetimepicker) First child of a Stack route should almost always be a ScrollView with INLINECODE49 Prefer headerSearchBarOptions in Stack.Screen options for search bars Use <Text selectable /> on data that users may want to copy Format large numbers: 1.4M, 38k Never use intrinsic elements (img, div) outside webviews or Expo DOM components
Styling
Follow Apple Human Interface Guidelines.
General Rules
- Prefer flex gap over margin and padding Prefer padding over margin Always account for safe area via stack headers, tabs, or INLINECODE54 Ensure both top and bottom safe area insets are handled Inline styles preferred over StyleSheet.create unless reusing styles Add entering/exiting animations for state changes Use { borderCurve: 'continuous' } for rounded corners (not capsule shapes) Use navigation stack title instead of custom text headers On ScrollView, use contentContainerStyle for padding/gap (avoids clipping) CSS and Tailwind are not supported — use inline styles
Text Styling
- Add selectable prop to <Text/> elements showing important data or errors Use { fontVariant: 'tabular-nums' } on counters for alignment
Shadows
Use CSS boxShadow style prop. Never use legacy RN shadow or elevation styles.
CODEBLOCK1
Inset shadows are supported.
Navigation
Link
Use <Link href="/path" /> from expo-router for navigation.
CODEBLOCK2
Include <Link.Preview> whenever possible to follow iOS conventions. Add context menus and previews frequently.
Stack
- Always use _layout.tsx files to define stacks Use Stack from expo-router/stack for native navigation stacks Set page titles in Stack.Screen options: INLINECODE68
Context Menus
Add long-press context menus to Link components:
CODEBLOCK3
Link Previews
CODEBLOCK4
Can be combined with context menus.
Modal
Present a screen as a modal:
CODEBLOCK5
Prefer this over custom modal components.
Sheet
Present as a dynamic form sheet:
CODEBLOCK6
INLINECODE69 enables liquid glass on iOS 26+.
Common Route Structure
Standard app layout with tabs and stacks:
CODEBLOCK7
Root layout:
CODEBLOCK8
Shared group layout:
CODEBLOCK9
使用 Expo Router 的原生 UI
使用 Expo Router 和 React Native 构建原生移动应用程序的模式和约定。
参考资料
根据需要查阅以下内容:
- ./references/route-structure.md — 路由约定、动态路由、分组、文件夹组织 ./references/tabs.md — 使用 NativeTabs 的原生标签栏,iOS 26 功能 ./references/icons.md — 使用 expo-symbols 的 SF Symbols,图标名称,动画,权重 ./references/controls.md — 原生 iOS 控件:Switch、Slider、SegmentedControl、DateTimePicker ./references/visual-effects.md — 模糊效果 (expo-blur) 和液态玻璃 (expo-glass-effect) ./references/animations.md — Reanimated:进入、退出、布局、滚动驱动、手势 ./references/search.md — 带标题的搜索栏,useSearch 钩子,过滤模式 ./references/gradients.md — 通过 experimental_backgroundImage 实现的 CSS 渐变(仅限新架构) ./references/media.md — 相机、音频、视频、文件保存 ./references/storage.md — SQLite、AsyncStorage、SecureStore ./references/webgpu-three.md — 使用 WebGPU/Three.js 的 3D 图形和 GPU 可视化 ./references/toolbar-and-headers.md — 带按钮、菜单、搜索栏的 Stack 标题和工具栏(iOS) ./references/form-sheet.md — 表单表单呈现模式
运行应用
在创建自定义构建之前,始终先尝试 Expo Go。
1. 使用 npx expo start 启动并扫描二维码 在 Expo Go 中测试功能 仅在需要时创建自定义构建
何时需要自定义构建
仅在以下情况下使用 npx expo run:ios/android 或 eas build:
- 本地 Expo 模块(modules/ 中的自定义原生代码) Apple 目标(通过 @bacons/apple-targets 的小部件、应用剪辑) Expo Go 中不包含的第三方原生模块 超出 app.json 的自定义原生配置
Expo Go 开箱即支持所有 expo-* 包、Expo Router、Reanimated、Gesture Handler、推送通知和深度链接。
安装
OpenClaw / Moltbot / Clawbot
bash
npx clawhub@latest install native-ui
代码风格
- 正确转义嵌套的反引号和引号 始终在文件顶部使用 import 语句 文件名使用 kebab-case:comment-card.tsx 重构导航时删除旧的路由文件 文件名中不要包含特殊字符 配置 tsconfig.json 路径别名;优先使用别名而非相对导入
路由
详细约定请参见 ./references/route-structure.md。
- 路由属于 app 目录 切勿将组件、类型或工具与 app/ 放在同一目录下——这是一种反模式 始终有一个匹配 / 的路由,可能位于分组路由内部
库偏好
使用 替代 expo-audio expo-av expo-video
expo-av |
| expo-symbols | @expo/vector-icons |
| react-native-safe-area-context | RN SafeAreaView |
| process.env.EXPO_OS | Platform.OS |
| React.use | React.useContext |
| expo-image | 原生 img 元素 |
| expo-glass-effect | 自定义玻璃背景 |
切勿使用已弃用的模块:Picker、WebView、SafeAreaView、AsyncStorage(来自 RN 核心)或旧版 expo-permissions。
响应式
- 将根组件包裹在滚动视图中 使用 替代 同样对 FlatList 和 SectionList 应用 contentInsetAdjustmentBehavior=automatic 使用 flexbox 替代 Dimensions API 屏幕测量优先使用 useWindowDimensions 而非 Dimensions.get()
行为
- 在 iOS 上有条件地使用 expo-haptics 实现愉悦的交互 使用内置触觉反馈的视图( 、@react-native-community/datetimepicker) Stack 路由的第一个子元素几乎始终应该是带有 contentInsetAdjustmentBehavior=automatic 的 ScrollView 搜索栏优先使用 Stack.Screen 选项中的 headerSearchBarOptions 对用户可能想要复制的数据使用 格式化大数字:1.4M、38k 切勿在 WebView 或 Expo DOM 组件之外使用原生元素(img、div)
样式
遵循 Apple 人机界面指南。
通用规则
- 优先使用 flex gap 而非 margin 和 padding 优先使用 padding 而非 margin 始终通过 stack 标题、标签栏或 contentInsetAdjustmentBehavior=automatic 处理安全区域 确保顶部和底部安全区域插入都已处理 除非复用样式,否则优先使用内联样式而非 StyleSheet.create 为状态变化添加进入/退出动画 使用 { borderCurve: continuous } 实现圆角(非胶囊形状) 使用导航栈标题而非自定义文本标题 在 ScrollView 上,使用 contentContainerStyle 设置 padding/gap(避免裁剪) 不支持 CSS 和 Tailwind——使用内联样式
文本样式
- 在显示重要数据或错误的 元素上添加 selectable 属性 在计数器上使用 { fontVariant: tabular-nums } 实现对齐
阴影
使用 CSS boxShadow 样式属性。切勿使用旧版 RN shadow 或 elevation 样式。
tsx
支持内阴影。
导航
Link
使用 expo-router 中的 进行导航。
tsx
import { Link } from expo-router;
...
尽可能包含 以遵循 iOS 约定。频繁添加上下文菜单和预览。
Stack
- 始终使用 _layout.tsx 文件定义栈 使用 expo-router/stack 中的 Stack 实现原生导航栈 在 Stack.Screen 选项中设置页面标题:options={{ title: Home }}
上下文菜单
为 Link 组件添加长按上下文菜单:
tsx
{}} />
{}} />
Link 预览
tsx
可以与上下文菜单结合使用。
模态
将屏幕呈现为模态:
tsx
优先使用此方式而非自定义模态组件。
表单
呈现为动态表单表单:
tsx
name=sheet
options={{
presentation: formSheet,
sheetGrabberVisible: true,
sheetAllowedDetents: [0.5, 1.0],
contentStyle: { backgroundColor: transparent },
}}
/>
contentStyle: { backgroundColor: transparent } 在 iOS 26+ 上启用液态玻璃效果。
常见路由结构
带标签栏和栈的标准应用布局:
app/
_layout.tsx —
(index