
Ever been caught in that in-between zone where you love react native for its cross-platform mobile development superpowers, but wish you could tap into SwiftUI’s native iOS finesse for those trickier moments? Yeah, we’ve been there too.
Imagine your app cruising along just fine using react native app development, but then you hit a screen that needs more. For instance, an AR view, a complex animation, or something that needs to feel deeply native on iOS. And suddenly, you’re thinking, “This would be so much easier in SwiftUI.”
Good news: you don’t have to choose one or the other. In this blog, I’ll walk you through how to embed SwiftUI screens right inside your react native app, smoothly and without a headache.
To make this all a bit more real, I’ll walk through a hands-on react native and SwiftUI tutorial that shows just how these technologies can play together. We’ll build a simple demo app with two connected screens that pass data back and forth in real time. Let’s dive in.
Step 1: Create a New React Native Project
Start by setting up a new React Native project:
npx @react-native-community/cli@latest init RNWithSwiftUI
Code language: CSS (css)
For teams targeting web and mobile together, react native expo with tamagui integration for web & mobile apps is another practical approach to unify your ui stack.
Step 2: Setup the iOS Native Module
Open the iOS directory in your project in Xcode, and add a new Swift file named NativeBridge.swift
import Foundation
import React
import SwiftUI
@objc(NativeBridge)
class NativeBridge: NSObject {
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
@objc
func openSwiftUIScreen(_ data: NSDictionary, callback: @escaping RCTResponseSenderBlock) {
DispatchQueue.main.async {
let swiftUIView = SwiftUIView(data: data) { result in
callback([result])
}
let hostingController = UIHostingController(rootView: swiftUIView)
hostingController.modalPresentationStyle = .fullScreen
let keyWindow = UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.compactMap { $0 as? UIWindowScene }
.first?.windows
.filter { $0.isKeyWindow }
.first
if let rootViewController = keyWindow?.rootViewController {
rootViewController.present(hostingController, animated: true)
}
}
}
}
- This NativeBridge acts as the main entry point for communication between React Native and native iOS code.
- The @objc(NativeBridge) annotation makes this Swift class available to Objective-C and React Native.
- requiresMainQueueSetup method tells React Native that this module needs to be initialized on the main thread.
- openSwiftUIScreen: This method is invoked from the React Native side.
First Parameter:
_ data: NSDictionary: Receives data from React Native.
Second Parameter:
callback: @escaping RCTResponseSenderBlock: Sends data back to React Native. - Presents the SwiftUIView view modally on the root view controller.
Planning to scale your app globally? See how to start adding multilingual support to your react native app for international readiness.

Step 3: Setup the SwiftUI View
Add a new SwiftUI View file to your iOS project.
import SwiftUI
struct SwiftUIView: View {
let data: NSDictionary
let callback: (NSDictionary) -> Void
@State private var text: String = ""
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationStack {
VStack {
Text("SwiftUI Screen")
.font(.title)
.padding()
Text("Data from React Native: \(data["message"] as? String ?? "")")
.padding()
TextField("Enter text", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Button("Send Data Back") {
let result: NSDictionary = ["response": text]
callback(result)
presentationMode.wrappedValue.dismiss()
}
.padding()
}
.padding()
.navigationTitle("SwitftUI")
.navigationBarTitleDisplayMode(.large)
}
}
}
Code language: JavaScript (javascript)
The SwiftUI view above takes care of a few key tasks:
- It displays the data received from React Native
- Let the user input new information
- Sends that updated data back to React Native
- And finally, it handles dismissing itself when done
This approach blends the benefits of hybrid mobile app development with the fluid UI capabilities of SwiftUI and shows the flexibility you get when you hire react native developers who know how to make both ecosystems work together effectively.
Step 4: Create the Objective-C interface file
Open the iOS directory in your project in Xcode, and add a new Objective C file NativeBridge.m

Add the below mentioned code block to it.
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(NativeBridge, NSObject)
RCT_EXTERN_METHOD(openSwiftUIScreen:(NSDictionary *)data
callback:(RCTResponseSenderBlock)callback)
@end
Code language: HTML, XML (xml)
The code block above handles the following tasks:
- Imports React Native’s bridge module header, required for creating native modules in React Native
- RCT_EXTERN_MODULE: React Native macro to expose a native module.
- NativeBridge: Name of the module (must match Swift class name created in Step 2).
- NSObject: Base class for the module.
- RCT_EXTERN_METHOD: Macro to expose a method to React Native.
- openSwiftUIScreen: Method name that is called from the RN side.
- (NSDictionary *)data: Parameter for receiving data from React Native.
- (RCTResponseSenderBlock)callback: Parameter for sending data back to React Native.
Step 5: Setup the React Native Part
Let’s create a HomeScreen.tsx file that includes a text field and a button. When the button is tapped, it will open a SwiftUI screen, passing along the text entered by the user. The screen will also display any data sent back from the SwiftUI side.
import React, {useState} from 'react'
import {
View,
Text,
TextInput,
Button,
NativeModules,
StyleSheet,
} from 'react-native';
const {NativeBridge} = NativeModules;
const HomeScreen = () => {
...
const openNativeScreen = () => {
const data = {
message: message
};
NativeBridge.openSwiftUIScreen(data, (result: any) => {
setResponse(result.response);
})
}
return (
<View style={styles.container}>
...
<TextInput
style={styles.input}
placeholder="Enter message for SwiftUI"
value={message}
onChangeText={setMessage}
/>
<Button title="Open SwiftUI Screen" onPress={openNativeScreen} />
{response ? (
<Text style={styles.response}>
Response from SwiftUI: {response}
</Text>
) : null}
</View>
)
}
export default HomeScreen
...
Code language: JavaScript (javascript)
Let’s explore the code in more detail.
const {NativeBridge} = NativeModules;
Code language: JavaScript (javascript)
- In the above block of code, we import the native module we created in Step 2 and make the NativeBridge available for use.
const openNativeScreen = () => {
const data = {
message: message
};
NativeBridge.openSwiftUIScreen(data, (result: any) => {
setResponse(result.response);
})
}
Code language: JavaScript (javascript)
- Creates a data object using the current message.
- Calls the native openSwiftUIScreen method to launch the SwiftUI screen.
- Sets up a callback to handle the response from SwiftUI.
- Updates the state with the returned data once it’s received.
We are almost done with the setup, let’s run and see our application in action.

Voila! We did it. The SwiftUI screen is now fully integrated into our react native app, and data flows back and forth seamlessly.
Summing It Up
I hope this tutorial helped demonstrate how to embed a SwiftUI screen within a react native app. To download the source code for the sample app, check it out on GitHub.
If you’re considering building such integrations and need expert assistance, refer to 8 factors to consider when choosing the right react native development company to make an informed decision.

Author's Bio

Prashant Telangi brings over 15 years of experience in Mobile Technology, He is currently serving as Head of Technology, Mobile at Mobisoft Infotech. With a proven history in IT and services, he is a skilled, passionate developer specializing in Mobile Applications. His strong engineering background underscores his commitment to crafting innovative solutions in the ever-evolving tech landscape.