Skip to content

How It Works

Markdown

React Native SwiftUI bridges React components to native SwiftUI views using Nitro Modules. This page explains the architecture and key concepts.

React Side (what you write):

<SwiftUI style={{ flex: 1 }}>
<SwiftUI.Form>
<SwiftUI.Section header="Profile">
<SwiftUI.TextField label="Name" text={name} onChange={setName} />
<SwiftUI.Toggle label="Active" isOn={active} onChange={setActive} />
</SwiftUI.Section>
</SwiftUI.Form>
</SwiftUI>

Native Side (what renders):

Form {
Section(header: Text("Profile")) {
TextField("Name", text: $name)
Toggle("Active", isOn: $active)
}
}

SwiftUI components don’t render React Native views. Instead, they register themselves in a virtual tree:

  • Components return null — No React Native views are created
  • Tree is serialized — Component hierarchy is passed to native code
  • Native rendering — SwiftUI renders the entire tree natively
// Each component registers itself with type and props
<SwiftUI.TextField label="Name" text={name} onChange={setName} />
// Internally creates a node:
// { type: "TextField", props: { label: "Name", text: "..." } }

The SwiftUI component acts as the bridge between React and native:

ResponsibilityDescription
Context ProviderManages component registration and event routing
Native View HostHosts the HybridSwiftUIRootView Nitro view
Tree SerializationConverts React tree to native view tree
Event DispatchRoutes native events to React handlers
<SwiftUI style={{ flex: 1 }} debug>
{/* All SwiftUI components must be inside this container */}
</SwiftUI>

Events flow from native SwiftUI back to React:

  1. User interaction — User taps toggle, types in text field
  2. Native event — SwiftUI fires change event with new value
  3. Bridge dispatch — Event sent through the Nitro JSI bridge to JavaScript
  4. Handler callback — Your onChange function is called
  5. State update — React re-renders with new value
<SwiftUI.TextField
text={value} // Current value passed to native
onChange={setValue} // Called when native value changes
onFocus={() => {}} // Called on native focus event
onBlur={() => {}} // Called on native blur event
/>

React Native styles are translated to SwiftUI modifiers:

React Native StyleSwiftUI Modifier
backgroundColor.background()
color.foregroundColor()
fontSize.font()
padding.padding()
borderRadius.cornerRadius()
<SwiftUI.Text
text="Hello"
style={{
color: '#007AFF',
fontSize: 18,
fontWeight: 'bold',
}}
/>
// Translates to SwiftUI:
// Text("Hello")
// .foregroundColor(Color(hex: "#007AFF"))
// .font(.system(size: 18, weight: .bold))

Unlike web-based or JavaScript-rendered UI:

  • No JavaScript layout — SwiftUI handles all layout natively
  • Native animations — System animations, not JavaScript-driven
  • 60fps guaranteed — No bridge overhead during interactions

Components match iOS exactly:

  • System fonts — SF Pro with proper weight mappings
  • System colors — Automatic dark mode support
  • Native behaviors — Keyboard handling, haptics, accessibility

Built on Nitro Modules for a direct JSI bridge to Swift:

  • Direct JSI calls — No serialization overhead between JS and Swift
  • Hybrid views — Each native view is a Swift HybridView subclass
  • Type-safe codegen — Swift/C++ bridge generated from src/specs/*.nitro.ts by Nitrogen

SwiftUI is an Apple framework. For cross-platform apps:

import { Platform } from 'react-native';
{Platform.OS === 'ios' ? (
<SwiftUI style={{ flex: 1 }}>
<SwiftUI.Form>...</SwiftUI.Form>
</SwiftUI>
) : (
<AndroidForm />
)}

React Native views cannot be placed inside the SwiftUI tree:

// ❌ Won't work
<SwiftUI.Form>
<View><Text>RN View inside SwiftUI</Text></View>
</SwiftUI.Form>
// ✅ Use SwiftUI components
<SwiftUI.Form>
<SwiftUI.Text text="SwiftUI Text" />
</SwiftUI.Form>

Requires React Native 0.78+ with the New Architecture enabled (a prerequisite of Nitro Modules). The legacy architecture is not supported.