Subchapter 21.3
references/swift-ui.mdMarkdown4 KBView on GitHub
@expo/ui/swift-uiiOS only. Code that imports from
@expo/ui/swift-uiwill crash on Android with “Unable to get view config” errors. Always place this code in an.ios.tsxcomponent file or guard it with . must be imported from (the universal root), not from .
Platform.OS === 'ios'Host@expo/ui@expo/ui/swift-uiUse this layer only when the universal @expo/ui components don’t cover what you need on iOS (see ./universal.md first). This requires a platform-specific tree.
Do not put .ios.tsx files inside app/ or src/app/. Expo Router does not support platform-extension suffixes for route files and will throw a “no fallback sibling” Render Error.
Place platform-specific component files in components/ (or any directory outside the route tree), then import them from a regular route file:
src/components/ProfileEditor.ios.tsx ← SwiftUI tree lives here
src/app/profile-editor.tsx ← regular Expo Router route, imports the componentsrc/app/profile-editor.tsx:
import ProfileEditor from '../components/ProfileEditor';
export default ProfileEditor;Alternatively, keep everything in one regular route file and branch on Platform.OS:
// src/app/profile-editor.tsx
import { Platform } from 'react-native';
// import SwiftUI components only when on iOS to avoid Android crash
const SwiftUIForm = Platform.OS === 'ios' ? require('../components/ProfileEditor.ios').default : null;Or more simply, put the Platform.OS guard and the SwiftUI import in the same route file (safe because Metro only bundles .ios.tsx imports on iOS builds when using platform extensions in components/).
@expo/ui/swift-ui, modifiers from @expo/ui/swift-ui/modifiers.node <skill-root>/scripts/list-components.js <project-path> # names only (compact)
node <skill-root>/scripts/list-components.js <project-path> --docs # with one-line descriptions<skill-root> is the directory containing this references/ folder.).d.ts) are the most reliable source of truth for prop shapes and signatures — read the relevant {Component}/index.d.ts from the installed @expo/ui/swift-ui package in node_modules. Use the docs below as the human-readable reference.Host.RNHostView is specifically for embedding RN components inside a SwiftUI tree. Example:import { Host } from "@expo/ui"; // Host always from universal root
import { VStack, RNHostView } from "@expo/ui/swift-ui"; // platform components from swift-ui
import { Pressable } from "react-native";
<Host matchContents>
<VStack>
<RNHostView matchContents>
// Here, `Pressable` is an RN component so it is wrapped in `RNHostView`.
<Pressable />
</RNHostView>
</VStack>
</Host>;useNativeState creates observable state that updates synchronously on the UI thread via worklets, enabling immediate native state changes without waiting for a React render cycle. Requires react-native-worklets — without it updates still go through React and flickering remains. Best for real-time interactions where synchronous updates matter, e.g. a text field that masks or formats input as the user types.
ObservableState.value is readable/writable from worklets; onChange fires a worklet listener on state change.