A proof-of-concept (PoC) library that integrates SwiftUI components into React Native using the Fabric renderer. This project enables developers to define native iOS UI elements with SwiftUI, controlled via React Native’s JSX syntax, creating a hybrid UI where React drives a dynamic SwiftUI view hierarchy.
React Native excels at cross-platform development, but its UI components can sometimes lack the polish and performance of native iOS frameworks like SwiftUI. This PoC bridges that gap by:
- Leveraging SwiftUI’s declarative, high-performance UI toolkit for iOS.
- Using React Native’s Fabric renderer for modern, efficient native integration.
- Enabling a familiar JSX workflow to manage native views.
Ideal for developers seeking native iOS aesthetics and behavior within a React Native app, this project explores a hybrid paradigm for enhanced UI flexibility.
- Supported Components: We plan to support as many SwiftUI components as possible.
- Two-Way Data Binding: Syncs state between JavaScript and SwiftUI (e.g., text input updates via
onChange
). - Event Support: Handles events like
change
,focus
,blur
,press
across the JS-native boundary. - Visual Feedback: Disabled fields (e.g.,
TextField
withdisabled={true}
) are grayed out and faded for clarity. - Type Safety: TypeScript definitions for props and events, ensuring a robust developer experience.
- Form Library Compatibility: Works seamlessly with libraries like
react-hook-form
andformik
via passthrough component support.
- Node.js ≥ 18
- React Native 0.78.0+
- iOS 15.1+ (SwiftUI requirement)
pnpm
(package manager, version 10.5.2 recommended perpackage.json
)
Installation steps:
npm install @mgcrea/react-native-swiftui --save
# or
pnpm add @mgcrea/react-native-swiftui
# or
yarn add @mgcrea/react-native-swiftui
import { SwiftUI } from "@mgcrea/react-native-swiftui";
import { useState, type FunctionComponent } from "react";
import { Alert, View } from "react-native";
export const BasicFormExample: FunctionComponent = () => {
const [firstName, setFirstName] = useState("John");
const [lastName, setLastName] = useState("Doe");
const [birthDate, setBirthDate] = useState(new Date("2019-06-03T00:00:00Z"));
const [gender, setGender] = useState<"Male" | "Female">("Male");
const handleSubmit = () => {
const data = {
firstName,
lastName,
birthDate,
gender,
};
Alert.alert("Submitted", JSON.stringify(data, null, 2));
};
return (
<View style={{ flex: 1 }}>
<SwiftUI style={{ flex: 1 }}>
<SwiftUI.Text text="BasicFormExample" />
<SwiftUI.Form>
<SwiftUI.Section header="Personal Information">
<SwiftUI.TextField placeholder="First name" onChange={setFirstName} text={firstName} />
<SwiftUI.TextField placeholder="Last name" onChange={setLastName} text={lastName} />
</SwiftUI.Section>
<SwiftUI.Section header="Additional Details">
<SwiftUI.Picker
options={["Male", "Female"]}
label="Gender"
onChange={setGender}
selection={gender}
/>
<SwiftUI.DatePicker
label="Birth date"
selection={birthDate}
onChange={(value) => setBirthDate(value)}
displayedComponents="date"
/>
</SwiftUI.Section>
<SwiftUI.Button title="Submit" onPress={handleSubmit} />
</SwiftUI.Form>
</SwiftUI>
</View>
);
};
Below is a list of components currently supported by @mgcrea/react-native-swiftui
. These components leverage SwiftUI's native iOS capabilities while being controlled via React Native's JSX syntax.
Component | Description | Key Props | Notes |
---|---|---|---|
Button |
A clickable button with customizable styles | title , buttonStyle , disabled , style , onPress |
Supports styles like default , plain , bordered , etc. |
DatePicker |
A date/time selection picker | selection , label , datePickerStyle , displayedComponents , onChange |
Options include compact , wheel , etc.; supports date , hourAndMinute components |
Form |
A container for grouping form elements | Children (nested components) | No specific props; acts as a layout container |
Group |
A logical grouping of views | Children (nested components) | No specific props; used for hierarchy organization |
HStack |
Horizontal stack layout | alignment , spacing , style , Children |
Alignments: top , center , bottom , etc. |
Image |
Displays an image (named, system, or local) | name , source , sourceUri , resizeMode , style |
Supports system: prefix for SF Symbols, asset names, and bundled assets via require |
Picker |
A dropdown or segmented selection | options , selection , label , pickerStyle , onChange |
Styles: menu , segmented , wheel , etc. |
Rectangle |
A simple rectangular shape | style |
Used for basic shapes with customizable styling |
Section |
A collapsible section within a form | header , footer , isCollapsed , Children |
Useful for organizing form content |
Sheet |
A modal sheet presentation | isPresented , detents , onDismiss , Children |
Detents: medium , large , or custom values |
Slider |
A continuous value slider | value , minimum , maximum , step , label , onChange |
Adjustable range with step increments |
Spacer |
A flexible space filler | minLength |
Expands to fill available space |
Stepper |
An increment/decrement control | value , label , minimum , maximum , step , onChange |
For numeric adjustments |
Text |
Displays static text | text , alignment , style |
Alignments: leading , center , trailing |
TextField |
An editable text input | text , label , placeholder , keyboardType , onChange |
Supports various keyboard types and text content types |
Toggle |
A switch for boolean values | isOn , label , onChange |
Simple on/off control |
VStack |
Vertical stack layout | alignment , spacing , style , Children |
Alignments: leading , center , trailing |
ZStack |
Overlapping stack layout | alignment , style , Children |
Alignments: topLeading , center , bottomTrailing , etc. |
- Props: Most components accept a
style
prop for layout and appearance customization (e.g.,width
,height
,backgroundColor
). - Events: Components like
Button
,TextField
, andPicker
support event handlers (e.g.,onPress
,onChange
) for interactivity. - Children: Layout components (
Form
,HStack
,VStack
, etc.) accept nested components as children. - Image Sources: The
Image
component supports:- Named assets from
Assets.xcassets
(e.g.,name="logo"
). - System images with a
system:
prefix (e.g.,name="system:star.fill"
). - Local bundled assets via
source={require('../path/to/image.png')}
.
- Named assets from
- Component-Level Tree Building: Each
SwiftUI.*
component (e.g.,<SwiftUI.TextField>
) registers itself with aviewTree
during React’s render phase, using a context-based system. - Native Rendering: The aggregated
viewTree
is serialized as JSON and sent to iOS, where SwiftUI renders it via Fabric’s native bridge. Components use a unifiedDecodable
approach for prop initialization. - Two-Way Binding: State updates (e.g., text input) sync between React and SwiftUI via event handlers, with props merged efficiently on updates.
- Event Handling: Native events (e.g.,
onChange
,onPress
) are bubbled back to JavaScript through a custom event system.
- React Native (JS/TS):
- Defines UI structure in JSX.
- Uses
SwiftUIContext
for event handling and node registration. - Uses
SwiftUIParentContext
to maintain parent-child hierarchy. - Components register their
ViewTreeNode
dynamically during render.
- Fabric: Facilitates communication between JavaScript and native code.
- SwiftUI (iOS):
- Renders the UI using native components (e.g.,
TextField
,Button
) based on theviewTree
. Props
classes (e.g.,PickerProps
) conform toDecodable
for initialization and usemerge(from:)
for updates, unifying prop handling.
- Renders the UI using native components (e.g.,
- Bridge: Custom Objective-C++ and Swift files (e.g.,
RCTSwiftUIRootView.mm
,SwiftUIRootView.swift
) manage data flow and event propagation.
- Dynamic
viewTree
Generation: Components register themselves viaSwiftUIContext.registerNode
, with hierarchy tracked usingSwiftUIParentContext
. This supports passthrough components (e.g.,<Controller />
fromreact-hook-form
) without explicit prop forwarding. - Context System:
SwiftUIContext
: Manages event handlers and thenodeRegistry
.SwiftUIParentContext
: ProvidesparentId
to child components viaParentIdProvider
, ensuring correct tree structure.
- Prop Initialization: Native
Props
classes useDecodable
to initialize from JSON, reducing redundancy and ensuring consistency acrossviewTree
and Fabric flows. - Rendering: Components return
null
in JSX, as the UI is fully handled by SwiftUI on the native side.
- State Management: The library is agnostic to state management. Use React state,
react-hook-form
,formik
, or any other library to manage form values. - Events: Pass callbacks like
onChange
oronPress
to handle native events in JavaScript. - Disabled Fields: Set
disabled={true}
on components likeTextField
to disable interaction, with visual feedback (grayed-out text and reduced opacity).
Feel free to fork the repo, experiment with new components, or suggest optimizations! Open issues or PRs on GitHub.