It’s fairly easy to get started using iOS Native components in React Native. At the time of writing, this is the example given in the React Native docs.
#import <MapKit/MapKit.h> | |
#import <React/RCTViewManager.h> | |
@interface RNTMapManager : RCTViewManager | |
@end | |
@implementation RNTMapManager | |
RCT_EXPORT_MODULE(RNTMap) | |
- (UIView *)view | |
{ | |
return [[MKMapView alloc] init]; | |
} | |
@end |
It’s straightforward – you subclass RCTViewManager
and implement a view
method that returns a UIView
. Obviously you’ll soon want to start creating more custom views. Like this UITextView
, for example:
// | |
// TextViewManager.m | |
// SwiftViewSchool | |
// | |
// Created by Tanner West on 8/16/23. | |
// | |
#import <UIKit/UIKit.h> | |
#import <React/RCTViewManager.h> | |
@interface RNTTextViewManager : RCTViewManager | |
@end | |
@implementation RNTTextViewManager | |
RCT_EXPORT_MODULE(RNTTextView) | |
- (UIView *)view | |
{ | |
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)]; | |
textView.text = @"Hello, iOS!"; | |
textView.font = [UIFont systemFontOfSize:48]; | |
textView.textColor = [UIColor purpleColor]; | |
return [textView init]; | |
} | |
@end |
…then we can import our native view in React Native…
import React from 'react'; | |
import {SafeAreaView, Text} from 'react-native'; | |
import {requireNativeComponent} from 'react-native'; | |
const TextView = requireNativeComponent('RNTTextView'); | |
function App(): JSX.Element { | |
return ( | |
<SafeAreaView style={{flex: 1}}> | |
<Text>Hello, React Native</Text> | |
<TextView style={{flex: 1}} /> | |
</SafeAreaView> | |
); | |
} | |
export default App; |
And our result will look something like this:

Nice! This is a good start towards learning to build custom components, but if you’re like me, you like to avoid Objective-C as much as possible, and would prefer to use Swift when you write iOS native code. Here’s how we’d do that.
First, let’s create a swift file. I’ll call it TextViewProvider
. When you create this file in Xcode, you should be asked whether you’d like to create a bridging header (if your project doesn’t already have one). Answer yes to this; the bridging header is what will make your Swift code available to your Objective-C code.
Our new file will look this this, which creates the same type of UITextView
as our original code, but in Swift.
// | |
// TextViewProvider.swift | |
// SwiftViewSchool | |
// | |
// Created by Tanner West on 8/16/23. | |
// | |
import Foundation | |
import UIKit | |
@objc class TextViewProvider: NSObject { | |
@objc func createTextView() -> UITextView { | |
let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 200, height: 100)) | |
textView.text = "Hello, from Swift World!" | |
textView.font = UIFont.systemFont(ofSize: 48) | |
textView.textColor = UIColor.blue | |
return textView | |
} | |
} |
…then, in our main RCTViewManager
class, we can make a couple of tweaks to get our view from the new swift class:
// | |
// TextViewManager.m | |
// SwiftViewSchool | |
// | |
// Created by Tanner West on 8/16/23. | |
// | |
#import <UIKit/UIKit.h> | |
#import <React/RCTViewManager.h> | |
#import "SwiftViewSchool-Swift.h" | |
@interface RNTTextViewManager : RCTViewManager | |
@end | |
@implementation RNTTextViewManager | |
RCT_EXPORT_MODULE(RNTTextView) | |
- (UIView *)view | |
{ | |
TextViewProvider *provider = [[TextViewProvider alloc] init]; | |
UITextView *textView = [provider createTextView]; | |
return textView; | |
} | |
@end |
Notice how we’ve imported SwiftViewSchool-Swift.h
in our file. This is a reference our bridging header, and it’s how our Objective-C code is able to access our Swift class. The naming convention for the import is {YourProjectName}-Swift.h
. You can see the header name under Build Settings > Swift Compiler – General.

Now, when we rebuild our app, we should the text view we created in Swift.

Another approach would be to subclass UITextView
with our Swift class:
// | |
// TextViewProvider.swift | |
// SwiftViewSchool | |
// | |
// Created by Tanner West on 8/16/23. | |
// | |
import Foundation | |
import UIKit | |
@objc class TextViewProvider: UITextView { | |
override init(frame: CGRect, textContainer: NSTextContainer?) { | |
super.init(frame: frame, textContainer: textContainer) | |
common() | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
common() | |
} | |
private func common() { | |
text = "Hello, from Swift World!" | |
font = .systemFont(ofSize: 48) | |
textColor = .blue | |
} | |
} |