React Native Web: Sharing Code Between Mobile and Browser
AI generated
RN
native
React Native / New Architecture
React Native Web
A realistic look at code sharing between mobile and browser

react-native-web renders the same View, Text and ScrollView primitives used on iOS and Android as regular DOM elements in the browser. This article looks at how that translation actually works, where styling and platform APIs create real limits, and how much code genuinely ends up shared once navigation, native hardware access and layout details enter the picture.

10 min read react-native-web Code Sharing Platform APIs

1. How react-native-web maps RN primitives onto DOM elements

react-native-web translates the fundamental React Native components like View, Text, ScrollView and Image at runtime into regular DOM elements, usually div, span and img, while simultaneously translating the StyleSheet API into CSS classes written into the document through its own, highly efficient insertion engine. From the calling component's perspective nothing changes, it keeps importing the same components from react-native, only the build process swaps the target module.

This translation works because React Native primitives were designed from the start to be deliberately platform-independent pure layout and presentation containers, without a fixed binding to UIKit or the Android view system. That very abstraction is what makes react-native-web possible in the first place, while a library that assumes native views directly, without a web fallback, cannot be automatically translated along with it.

2. Setup in an existing RN project: bundler alias and webpack/Metro config

In an existing React Native project, react-native-web is usually wired in through an additional webpack or Vite configuration that redirects the react-native module to react-native-web via an alias, while Metro remains unchanged for native builds. For React Native projects already using Expo, Expo's webpack support handles this redirection largely automatically once the web target is enabled.

It is important to configure bundle splitting cleanly per platform, so that platform-specific code that only exists on iOS or Android does not accidentally end up in the web bundle and fail there at build time. A strict separation via file extensions combined with an explicit resolver order that tells the bundler which extension has priority for which target is the common approach.

3. Styling differences: StyleSheet, flexbox defaults and media queries

React Native defaults to flexDirection: column, while CSS in the browser defaults to row for flexbox direction. react-native-web automatically compensates for this difference for its own primitives, but any CSS written directly outside StyleSheet objects has to account for that difference deliberately, or layouts that look correct on mobile unexpectedly break in the browser.

Media queries do not exist in the original React Native StyleSheet model, which means responsive layouts for the web need additional tools like useWindowDimensions or a dedicated responsive library that reacts to breakpoints at runtime, instead of relying on declarative CSS media queries as the web normally would. This is one of the points where shared code most often needs extra platform logic.

4. Platform-specific APIs: Platform.select and .web.tsx file extensions

For code that fundamentally has to behave differently on one platform, React Native offers two established mechanisms: Platform.select for small, inline branched values within a single file, and file-based platform extensions like Button.web.tsx and Button.native.tsx for entirely different implementations that the bundler automatically picks based on the target platform.

In practice, Platform.select suits small, isolated differences like a slightly different shadow style, while file-based extensions pay off for components that need fundamentally different implementations on web and mobile, for example a map view that relies on a JavaScript library in the browser and a native SDK on mobile.

React Navigation generally supports react-native-web and translates navigation transitions into URL changes via the History API when a matching linking configuration block is provided. For simple stack navigation this works well, but more demanding, web-typical requirements like deeply nested, SEO-relevant server-side routing run into the limits of a navigation system primarily designed for native apps.

Projects with high demands on classic web routing, for example publicly indexed marketing pages, often replace navigation entirely in the web build with a dedicated web framework like Next.js, while shared content components continue to be imported from the common React Native codebase. Navigation itself is one of the areas that realistically tends to stay platform-specific.

6. Limits: native APIs without a web equivalent

Camera access, Bluetooth, native push notifications, biometrics and many other native modules simply have no direct web equivalent, because the browser either offers no access to the corresponding hardware at all or uses a completely different API model, for example the browser's MediaDevices API instead of a native camera SDK. For such cases nothing remains but writing a dedicated web implementation or deliberately disabling the feature in the web build.

Libraries from the React Native ecosystem that do not support a web target themselves, for example specialized native UI components, cannot automatically be used either. Before committing to react-native-web it pays off to take stock of which existing dependencies even ship a web target, rather than discovering that gap in the middle of a project.

7. A practical example: a shared button component for both platforms

A good candidate for genuine code sharing is a simple, presentational component like a button that only needs text, color and a press handler, without any platform-specific native dependency. As long as it uses only React Native primitives, the exact same file works unchanged on iOS, Android and in the web build through react-native-web.

The example below shows exactly such a component, free of any platform-specific branching, yet rendered identically across all three targets.


import { Pressable, Text, StyleSheet } from "react-native";

type Props = {
  label: string;
  onPress: () => void;
};

export function SharedButton({ label, onPress }: Props) {
  return (
    <Pressable style={styles.button} onPress={onPress}>
      <Text style={styles.label}>{label}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    paddingVertical: 12,
    paddingHorizontal: 20,
    borderRadius: 8,
    backgroundColor: "#4338ca",
  },
  label: {
    color: "#ffffff",
    fontWeight: "600",
    textAlign: "center",
  },
});

8. A realistic estimate: how much code actually gets shared

In practice, pure business logic, meaning validation, data processing, API clients and state management, can be shared nearly completely, since these layers are inherently independent of platform-specific UI details. The share of shared code for UI components, on the other hand, drops noticeably once layout nuances, gestures or platform-typical interaction patterns come into play, which mobile and the web expect differently.

Realistic projects often reach a code-sharing rate between 60 and 80 percent for application logic, but noticeably less for the actually visible surface, where hover states, keyboard navigation and web-typical layout patterns need their own adjustments. Anyone setting a 100 percent code-sharing rate as a goal usually underestimates how differently users actually behave on touchscreens versus with a mouse and keyboard.

9. Performance and bundle size considerations for the web target

A web build through react-native-web inevitably brings some runtime overhead, because the StyleSheet-to-CSS translation and the primitive abstraction happen at runtime in the browser instead of being converted into pure, minimal CSS already at build time. For most applications this overhead is negligible, but it can become noticeable on very performance-sensitive marketing or landing pages, where every millisecond of load time counts.

Bundle size can be reduced significantly through consistent code splitting per route and by excluding native, web-unused dependencies from the web bundle. A carefully configured bundler alias that never resolves native-only packages in the web build in the first place prevents unnecessary native code from ending up in the browser bundle and unnecessarily extending initial load time.

Area Share of shared code Typical limitation Recommendation
Business logic & state Very high, usually 80-100% Rarely platform-specific Keep fully shared
API clients & data processing Very high Network APIs are mostly platform-independent Shared modules without platform branches
Presentational UI components Medium, usually 50-70% Styling details, interaction patterns Adjust selectively with Platform.select
Navigation & routing Low Web routing requirements diverge strongly Often deliberately kept platform-specific
Native hardware features Very low to none No direct web equivalent Dedicated web implementation or feature flag

Mironsoft

React Native app development and Magento integration

A mobile app for the Magento shop that actually runs smoothly?

We build React Native apps cleanly connected to the Magento REST or GraphQL API, from the first line of code to publishing on the App Store and Google Play.

App Concept

Plan the architecture and feature scope of a Magento-connected app together.

Magento API Integration

Cleanly connect product catalog, cart, and checkout to the shop API.

Store Publishing

Guide the App Store and Google Play release process without pitfalls.

10. Summary

React Native Web Code Sharing at a Glance

How it works

react-native-web translates RN primitives into DOM elements at runtime and StyleSheet objects into CSS classes.

Setup

A bundler alias redirects react-native to react-native-web in the web build, Metro stays unchanged for native builds.

Realistic rate

Business logic can be shared almost completely, UI nuances and navigation noticeably less.

Limits

Native hardware features and platform-specific libraries without a web target cannot be used automatically.

11. FAQ: React Native Web Code Sharing at a Glance

1Do I have to rewrite my entire codebase for react-native-web?
No, as long as components use only React Native primitives, they usually work unchanged in the web build. Only platform-specific parts need dedicated adjustments.
2Does React Navigation work with react-native-web?
Yes, for simple stack navigation through a linking configuration that maps URL changes to the History API. More complex web routing requirements do run into limits though.
3How does flexbox differ between React Native and CSS on the web?
React Native defaults to flexDirection column, CSS on the web defaults to row. react-native-web compensates automatically for its own primitives, but directly written CSS needs to account for the difference itself.
4Can I use native modules like camera access in the web build?
Not directly, since the browser uses a completely different API model. Such features need a dedicated web implementation or get disabled in the web build.
5How high is the realistic code-sharing rate?
Often 80 to 100 percent for business logic and state management, noticeably less for visible UI components, typically between 50 and 70 percent.
6What is the difference between Platform.select and .web.tsx files?
Platform.select suits small, inline branched values within a single file, file-based extensions suit entirely different implementations of the same component.
7Do I need media queries in React Native Web?
The native StyleSheet model does not support media queries, so responsive layouts for the web need additional tools like useWindowDimensions or a dedicated responsive library.
8Is react-native-web worth it for an SEO-relevant marketing page?
Only to a limited extent usually, since classic server-side routing and SEO nuances are often better handled with a dedicated web framework like Next.js, while content components can still be shared.
9Does react-native-web noticeably increase bundle size on the web?
There is some runtime overhead from the StyleSheet-to-CSS translation, which can be significantly reduced through code splitting and excluding native dependencies from the web bundle.
10Can I use Expo for react-native-web?
Yes, Expo's webpack support handles the redirection from react-native to react-native-web largely automatically once the web target is enabled.