React Native for Web is an open source project that enables you to use React Native core components in React web applications. React Native for Web uses React DOM to render JavaScript code that is compatible with React Native in a web browser, making code sharing possible.
In this tutorial, weβll set up a React web app using Parcel, build components using React Native core components, and finally, share these components between our mobile and web applications with React Native for Web.
Letβs get started!
First, weβll create a new React Native app. For this demonstration, Iβm using npx, but you can also use the react-native-cli
package if it is installed globally on your development environment.
Open up a new terminal window and execute the following command:
npx react-native init MyApp
MyApp
is a placeholder for the name of your React Native project.
If you are using iOS Simulator, run yarn run ios
. If youβre using an emulator for Android, run yarn run android
. Once the build process is complete, youβll see the default React Native app with the boilerplate code, which you can modify inside of App.js
.
As an example, Iβll render a simple text message inside of App.js
:
import React from 'react'; import { View, StyleSheet, Text } from 'react-native'; const styles = StyleSheet.create({ screenContainer: { flex: 1 }, text: { fontSize: 20, color: 'cornflowerblue', marginTop: 50, alignSelf: 'center' } }); const App = () => { return ( <View styles={styles.screenContainer}> <Text style={styles.text}>I'm a React Native component</Text> </View> ); }; export default App;
The output of the code above will look like the image below:
Weβll use Parcel, a bundler that requires zero configuration, to easily set up a new web app in React. Setting up a React app using Parcel follows a similar paradigm to generating an app using Create React App.
Create a new directory inside of your React Native project called web/
. Inside, weβll create the following files and add the respective boilerplate code.
Create a file called index.html
and add the following code:
<html> <body> <div id="root"></div> <script src="./index.js"></script> </body> </html>
Create an App.js
file and add the following code to render a text inside of the h2
tag:
import React from 'react'; const WebAppTitle = () => { return ( <div> <h2 style={{ color: '#9400d3', fontSize: '32' }}> I'm a React app component. </h2> </div> ); }; const App = () => { return ( <> <WebAppTitle /> </> ); }; export default App;
Note that the WebAppTitle
is a custom web component. Now, weβll create an index.js
file and add the following code:
import React from 'react'; import { render } from 'react-dom'; import App from './App'; render(<App />, document.getElementById('root'));
Next, weβll initialize a React app with yarn init
, which will open an interactive session for you to create a package.json
file and add the required defaults. However, you can skip this session by running the shorthand yarn init --yes
.
After running yarn init --yes
, the package.json
file should look like the code below:
{ "name": "web", "version": "1.0.0", "main": "index.js", "license": "MIT" }
Next, install the following dependencies inside of the web
directory:
yarn add react react-dom react-native-web yarn add -D parcel-bundler
Parcel can take any file as an entry point, but an HTML or a JavaScript file is recommended for a web app. Now, weβll add the following scripts
to the package.json
file:
{ "scripts": { "start": "parcel serve ./index.html", "build": "parcel build ./index.html" } }
Bundling our web app with Parcel requires a custom setup. To configure Parcel to add an alias for the react-native-web
package, add the following code to package.json
:
{ "alias": { "react-native": "react-native-web" } }
The complete package.json
file should look like the following code block:
{ "name": "web", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "react": "17.0.2", "react-dom": "17.0.2", "react-native-web": "0.17.1" }, "devDependencies": { "parcel-bundler": "1.12.5" }, "scripts": { "start": "parcel serve ./index.html", "build": "parcel build ./index.html" }, "alias": { "react-native": "react-native-web" } }
To start the development server for the web app, run yarn start
from the terminal window. Parcel will build the web app and serve it on http://localhost:1234
:
Now that weβve set up a React Native app and a React web app, letβs create a shared component that we can use in both.
Inside the root directory of your project, create a new subdirectory called shared
. The subdirectoryβs name indicates that anything inside of it is shared between the web and mobile apps. Inside of shared
, create another subdirectory called components
.
Letβs create a file called Header.js
, which will contain styles to display a header with a title. Add the following code to Header.js
:
import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; const styles = StyleSheet.create({ header: { paddingTop: 50, backgroundColor: 'blue' }, headerText: { fontSize: 22, color: 'white', fontWeight: 'bold', paddingHorizontal: 10 } }); const Header = () => { return ( <View style={styles.header}> <Text style={styles.headerText}>I'm a shared component.</Text> </View> ); }; export default Header;
Next, add the component to the App.js
file in the root directory of your project:
// add this after other import statements import Header from './shared/components/Header'; // Modify the JSX in App component const App = () => { return ( <View styles={styles.screenContainer}> <Header /> <Text style={styles.text}>I'm a React Native component</Text> </View> ); };
Youβll have to add a symbolic link to the shared
directory for the web app, which is used to reference the contents of a directory at a specific location. Make sure you are in the web
directory and run the following command in the terminal window:
ln -s /Users/<your-os-username>/<path-to-the-shared-directory>/shared
The command above will create a reference to the shared
directory inside of the web
directory. Now, you can import the Header
component inside the web/App.js
file the same way you imported the React Native app:
// web/App.js import React from 'react'; import Header from './shared/components/Header'; const WebAppTitle = () => { return ( <div> <h2 style={{ color: '#9400d3', fontSize: '32' }}> I'm a React app component. </h2> </div> ); }; const App = () => { return ( <> <Header /> <WebAppTitle /> </> ); }; export default App;
Run yarn start
to restart the development for the web app. The output of this command will look like the image below:
If you want to see how React Native for Web builds the DOM elements in the web browser, open up Developer Tools and navigate to the Elements tab. You can also right-click on the web page and select Inspect Element:
On closer look, youβll see that React Native for Web converts React Native styles and components to DOM elements. When styling components, React Native uses JavaScript objects. React Native for Web implements the React Native style API.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps β try LogRocket for free.
Hey there, want to help make our blog better?
Join LogRocketβs Content Advisory Board. Youβll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.