expo-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Expo @expo/ui SwiftUI Best Practices

Expo @expo/ui SwiftUI 最佳实践

Library reference for
@expo/ui/swift-ui
and
@expo/ui/swift-ui/modifiers
— the iOS surface of Expo's native UI bridge. Contains 53 rules across 8 categories, prioritised by cascade impact for agents building Expo apps that render to native SwiftUI views on iOS 26 and earlier.
@expo/ui/swift-ui
@expo/ui/swift-ui/modifiers
的库参考文档——Expo原生UI桥接的iOS端实现。包含8个类别下的53条规则,按影响层级排序,供开发Expo应用的Agent参考,这些应用需在iOS 26及更早版本上渲染原生SwiftUI视图。

When to Apply

适用场景

Reference these guidelines when:
  • Building a new screen with
    @expo/ui/swift-ui
    — pick the right container (Form vs List vs ScrollView), wrap in Host correctly, apply modifiers
  • Migrating from React Native primitives (View, Text, TouchableOpacity) to native SwiftUI components
  • Targeting iOS 26 features — Liquid Glass material, GlassEffectContainer, new sheet detent behaviours
  • Reviewing code that imports from
    @expo/ui/swift-ui
    or
    @expo/ui/swift-ui/modifiers
  • Debugging "the SwiftUI view doesn't render / is the wrong size / ignores styles" — usually a Host or modifier issue
  • Composing presentation surfaces — Alert, ConfirmationDialog, BottomSheet, Popover — under HIG modality guidance
  • Writing controlled inputs (TextField, Toggle, Picker, Slider) with
    useNativeState
    and worklet writes
在以下场景中参考本指南:
  • 使用
    @expo/ui/swift-ui
    构建新页面——选择合适的容器(Form/List/ScrollView)、正确用Host包裹、应用修饰符
  • 从React Native基础组件(View、Text、TouchableOpacity)迁移至原生SwiftUI组件
  • 开发iOS 26特性相关功能——Liquid Glass材质、GlassEffectContainer、全新sheet detent行为
  • 审查导入
    @expo/ui/swift-ui
    @expo/ui/swift-ui/modifiers
    的代码
  • 调试「SwiftUI视图不渲染/尺寸错误/忽略样式」问题——通常是Host或修饰符的问题
  • 遵循HIG模态规范构建展示层——Alert、ConfirmationDialog、BottomSheet、Popover
  • 使用
    useNativeState
    和worklet写入实现受控输入(TextField、Toggle、Picker、Slider)

When NOT to Use This Skill

不适用场景

  • Android Jetpack Compose — this skill covers iOS SwiftUI only. The
    @expo/ui/jetpack-compose
    surface has its own conventions
  • Universal (cross-platform) components
    @expo/ui
    exposes a small set; this skill scopes to the platform-specific iOS surface
  • Navigation routing — for stack/tab routing, use
    expo-router
    and
    expo-router/unstable-native-tabs
    ; this skill covers UI composition only
  • Pre-iOS-17 fallbacks — most rules assume iOS 17 minimum; Liquid Glass rules require iOS 26
  • Android Jetpack Compose——本技能仅覆盖iOS SwiftUI。
    @expo/ui/jetpack-compose
    端有独立的规范
  • 跨平台通用组件——
    @expo/ui
    提供少量此类组件;本技能聚焦于iOS平台专属的实现
  • 导航路由——栈/标签路由请使用
    expo-router
    expo-router/unstable-native-tabs
    ;本技能仅覆盖UI组合
  • iOS 17之前版本的兼容处理——多数规则假设最低支持iOS 17;Liquid Glass相关规则要求iOS 26

Rule Categories by Priority

按优先级划分的规则类别

PriorityCategoryImpactPrefix
1Setup & Host BoundariesCRITICAL
host-
2iOS 26 HIG Composition RulesCRITICAL
hig-
3Modifiers SystemCRITICAL
mod-
4Layout ComponentsHIGH
layout-
5Input & ControlsHIGH
input-
6Navigation & OverlaysHIGH
nav-
7Display & FeedbackMEDIUM-HIGH
display-
8State & Cross-Cutting PatternsMEDIUM
state-
优先级类别影响程度前缀
1配置与Host边界关键
host-
2iOS 26 HIG组合规则关键
hig-
3修饰符系统关键
mod-
4布局组件
layout-
5输入与控件
input-
6导航与浮层
nav-
7展示与反馈中高
display-
8状态与跨领域模式
state-

Quick Reference

快速参考

1. Setup & Host Boundaries (CRITICAL)

1. 配置与Host边界(关键)

  • host-wrap-all-swiftui-roots
    — Wrap every SwiftUI subtree in a Host
  • host-match-contents
    — Size Host to its SwiftUI content with matchContents
  • host-viewport-size-for-form
    — Use useViewportSizeMeasurement for Form and List
  • host-color-scheme-explicit
    — Pass explicit colorScheme when overriding the system
  • host-ignore-safe-area
    — Use ignoreSafeArea only for full-bleed surfaces
  • host-wrap-all-swiftui-roots
    — 将每个SwiftUI子树包裹在Host中
  • host-match-contents
    — 使用matchContents让Host尺寸匹配其SwiftUI内容
  • host-viewport-size-for-form
    — 为Form和List使用useViewportSizeMeasurement
  • host-color-scheme-explicit
    — 覆盖系统配色时传入明确的colorScheme
  • host-ignore-safe-area
    — 仅在全屏内容场景下使用ignoreSafeArea

2. iOS 26 HIG Composition Rules (CRITICAL)

2. iOS 26 HIG组合规则(关键)

  • hig-glass-effect-container
    — Group glass siblings inside GlassEffectContainer
  • hig-no-glass-on-glass
    — Avoid nesting glassEffect on glass surfaces
  • hig-no-stacked-modals
    — Resolve a sheet before presenting another
  • hig-popover-iphone-fallback
    — Don't use Popover on iPhone — use BottomSheet
  • hig-sheet-detents-partial
    — Include a partial detent for Liquid Glass appearance
  • hig-confirmation-dialog-destructive
    — ConfirmationDialog + destructive role
  • hig-tint-only-for-brand
    — Reserve tint for brand surfaces, not destructive
  • hig-glass-effect-container
    — 将玻璃效果的同级组件放入GlassEffectContainer中
  • hig-no-glass-on-glass
    — 避免在玻璃表面嵌套glassEffect
  • hig-no-stacked-modals
    — 关闭一个弹窗后再展示另一个
  • hig-popover-iphone-fallback
    — iPhone上不要使用Popover,改用BottomSheet
  • hig-sheet-detents-partial
    — 为Liquid Glass外观添加部分展开的detent
  • hig-confirmation-dialog-destructive
    — 为ConfirmationDialog设置destructive角色
  • hig-tint-only-for-brand
    — 仅在品牌专属场景使用tint,不要用于破坏性操作

3. Modifiers System (CRITICAL)

3. 修饰符系统(关键)

  • mod-prop-not-style
    — Modifiers go through the
    modifiers
    prop, not RN style
  • mod-composition-order
    — Modifier order is meaningful — each wraps the previous
  • mod-import-from-modifiers-subpath
    — Import from
    @expo/ui/swift-ui/modifiers
  • mod-frame-vs-fixedsize
    — frame proposes a size, fixedSize opts out of flex
  • mod-padding-vs-frame
    — padding for inner space, frame for outer bounds
  • mod-presentation-on-sheet-content
    — Presentation modifiers attach to sheet content
  • mod-disabled-prop
    — Use disabled modifier, don't conditionally render
  • mod-animation-wraps-trigger
    — withAnimation wraps state-driven prop changes
  • mod-prop-not-style
    — 修饰符通过
    modifiers
    属性传递,而非RN的style
  • mod-composition-order
    — 修饰符顺序有意义——每个修饰符包裹前一个
  • mod-import-from-modifiers-subpath
    — 从
    @expo/ui/swift-ui/modifiers
    导入
  • mod-frame-vs-fixedsize
    — frame用于提议尺寸,fixedSize用于退出flex布局
  • mod-padding-vs-frame
    — padding用于内部间距,frame用于外部边界
  • mod-presentation-on-sheet-content
    — 展示类修饰符附加到sheet内容上
  • mod-disabled-prop
    — 使用disabled修饰符,不要条件渲染
  • mod-animation-wraps-trigger
    — withAnimation包裹状态驱动的属性变更

4. Layout Components (HIGH)

4. 布局组件(高)

  • layout-hstack-vs-vstack
    — Pick stack direction by content flow
  • layout-lazy-stack-for-long-lists
    — LazyVStack inside ScrollView for long lists
  • layout-form-for-settings
    — Form adopts iOS grouped chrome automatically
  • layout-section-with-header-footer
    — Use Section header/footer slots
  • layout-scrollview-axes
    — Set axes explicitly for horizontal/2D scroll
  • layout-grid-vs-stack
    — Grid for column-aligned content
  • layout-hstack-vs-vstack
    — 根据内容流向选择栈方向
  • layout-lazy-stack-for-long-lists
    — 长列表使用ScrollView嵌套LazyVStack
  • layout-form-for-settings
    — Form会自动适配iOS分组样式
  • layout-section-with-header-footer
    — 使用Section的header/footer插槽
  • layout-scrollview-axes
    — 明确设置水平/二维滚动的axes
  • layout-grid-vs-stack
    — 列对齐内容使用Grid

5. Input & Controls (HIGH)

5. 输入与控件(高)

  • input-button-role-for-destructive
    — Set role='destructive' for delete buttons
  • input-button-systemimage
    — Use systemImage SF Symbol for button icons
  • input-textfield-observable-state
    — useNativeState for TextField, not React state
  • input-securefield-for-passwords
    — SecureField for passwords, not TextField
  • input-toggle-on-async
    — SyncToggle for instant flicks, Toggle for async
  • input-picker-style-via-modifier
    — pickerStyle modifier picks appearance
  • input-date-picker-range
    — Constrain selectable dates with range
  • input-stepper-bounded
    — Provide min and max on Stepper
  • input-button-role-for-destructive
    — 为删除按钮设置role='destructive'
  • input-button-systemimage
    — 按钮图标使用systemImage SF Symbol
  • input-textfield-observable-state
    — TextField使用useNativeState,而非React状态
  • input-securefield-for-passwords
    — 密码输入使用SecureField,而非TextField
  • input-toggle-on-async
    — 即时切换用SyncToggle,异步切换用Toggle
  • input-picker-style-via-modifier
    — 使用pickerStyle修饰符设置外观
  • input-date-picker-range
    — 用range约束可选日期范围
  • input-stepper-bounded
    — 为Stepper设置min和max值

6. Navigation & Overlays (HIGH)

6. 导航与浮层(高)

  • nav-alert-for-critical-only
    — Alert for blocking notifications only
  • nav-context-menu-vs-swipe
    — ContextMenu or SwipeActions per row, not both
  • nav-bottom-sheet-via-group
    — Wrap BottomSheet content in Group
  • nav-share-link-system
    — ShareLink for the system share sheet
  • nav-tabview-style-modifier
    — tabViewStyle modifier picks appearance
  • nav-disclosure-group-collapsible
    — DisclosureGroup for collapsible sections
  • nav-link-not-button-for-urls
    — Link for URLs, Button for in-app actions
  • nav-menu-primary-action
    — onPrimaryAction disambiguates tap from long-press
  • nav-alert-for-critical-only
    — Alert仅用于阻塞式通知
  • nav-context-menu-vs-swipe
    — 每行使用ContextMenu或SwipeActions,不要同时使用
  • nav-bottom-sheet-via-group
    — 将BottomSheet内容包裹在Group中
  • nav-share-link-system
    — 使用ShareLink调用系统分享面板
  • nav-tabview-style-modifier
    — 使用tabViewStyle修饰符设置外观
  • nav-disclosure-group-collapsible
    — 使用DisclosureGroup实现可折叠区域
  • nav-link-not-button-for-urls
    — 跳转URL用Link,应用内操作用Button
  • nav-menu-primary-action
    — 使用onPrimaryAction区分点击与长按操作

7. Display & Feedback (MEDIUM-HIGH)

7. 展示与反馈(中高)

  • display-text-markdown
    — Enable markdownEnabled for inline rich text
  • display-image-system-name
    — Prefer systemName SF Symbols over uiImage
  • display-chart-data-points
    — ChartDataPoint arrays drive native axes
  • display-gauge-current-value-label
    — Provide currentValueLabel for accessibility
  • display-progress-indeterminate
    — Undefined value → spinner, 0 → frozen bar
  • display-label-icon-vs-title
    — systemImage for SF Symbols, icon slot for custom
  • display-text-markdown
    — 启用markdownEnabled支持内嵌富文本
  • display-image-system-name
    — 优先使用systemName SF Symbols,而非uiImage
  • display-chart-data-points
    — 用ChartDataPoint数组驱动原生坐标轴
  • display-gauge-current-value-label
    — 提供currentValueLabel以支持无障碍访问
  • display-progress-indeterminate
    — 值为undefined时显示 spinner,值为0时显示冻结进度条
  • display-label-icon-vs-title
    — SF Symbols用systemImage,自定义图标用icon插槽

8. State & Cross-Cutting Patterns (MEDIUM)

8. 状态与跨领域模式(中)

  • state-use-native-state-for-fields
    — useNativeState for every bridged input
  • state-worklet-writes
    — Update ObservableState from worklets
  • state-controlled-via-selection-prop
    — selection or defaultSelection, not both
  • state-platform-check-pre-26
    — Guard iOS 26-only features with version check
  • state-textfield-ref-imperative
    — TextFieldRef for focus and selection
  • state-use-native-state-for-fields
    — 每个桥接输入都使用useNativeState
  • state-worklet-writes
    — 从worklets更新ObservableState
  • state-controlled-via-selection-prop
    — 使用selection或defaultSelection,不要同时使用
  • state-platform-check-pre-26
    — 用版本检查保护iOS 26专属特性
  • state-textfield-ref-imperative
    — 使用TextFieldRef处理焦点与选中文本

How to Use

使用方法

Read individual reference files for detailed explanations and code examples:
  • Section definitions — Category structure and impact levels
  • Rule template — Template for adding new rules
  • Reference files:
    references/{prefix}-{slug}.md
Each rule file contains:
  • Brief explanation of why it matters in the SwiftUI bridge
  • Incorrect code example anchored to a realistic domain
  • Correct code example with a minimal diff from the incorrect one
  • Where relevant: Alternative approach, When NOT to use, Warning callouts, authoritative reference URL
阅读单个参考文件获取详细说明和代码示例:
  • 章节定义 — 类别结构与影响层级
  • 规则模板 — 添加新规则的模板
  • 参考文件:
    references/{prefix}-{slug}.md
每个规则文件包含:
  • 该规则在SwiftUI桥接中重要性的简要说明
  • 基于真实场景的错误代码示例
  • 与错误示例差异最小的正确代码示例
  • 相关内容:替代方案、不适用场景、警告提示、权威参考链接

Gotchas

常见陷阱

See gotchas.md — append entries as failure points surface during real use.
详见gotchas.md — 在实际使用中遇到问题时可添加新条目。

Related Skills

相关技能

  • For Android Jetpack Compose components, the parallel skill would target
    @expo/ui/jetpack-compose
  • For navigation routing (stack, tabs), use
    expo-router
    directly
  • For form validation libraries, see the
    react-hook-form
    skill
  • Android Jetpack Compose组件相关内容,请参考针对
    @expo/ui/jetpack-compose
    的平行技能
  • 导航路由(栈、标签)请直接使用
    expo-router
  • 表单验证库相关内容,请查看
    react-hook-form
    技能