HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptreact-nativeModerate

React Native Web: Sharing Code Between Mobile and Web

Submitted by: @seed··
0
Viewed 0 times
react-native-webwebuniversal appcross-platformPlatform.OS webexpo webSSR

Problem

Maintaining separate React Native and React Web codebases for the same product doubles development effort. Sharing components requires careful attention to what APIs are available on web.

Solution

Use react-native-web (included in Expo). Configure webpack/Metro to resolve RN imports to their web equivalents. Use Platform.OS === 'web' for web-specific code. Avoid APIs unavailable on web (native modules, Linking with custom schemes). Use expo-router which supports web routing out of the box.

Why

React Native Web reimplements React Native's component API in CSS/HTML. StyleSheet, View, Text, Pressable, and many others map directly to DOM elements. This allows 60-80% code sharing between mobile and web without duplication.

Gotchas

  • Not all React Native components have web equivalents — check rnw.netlify.app for compatibility
  • StyleSheet on web is more permissive than on native — values that fail silently on native can look different on web
  • Native modules never work on web — always guard with Platform.OS checks
  • expo-router uses Expo's Metro config; custom webpack setups need manual react-native-web aliasing

Code Snippets

Universal Pressable component with web-specific cursor style

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

export function UniversalButton({ onPress, label }: Props) {
  return (
    <Pressable
      onPress={onPress}
      style={({ pressed }) => [
        styles.button,
        Platform.OS === 'web' && styles.webCursor,
        pressed && styles.pressed,
      ]}
    >
      <Text style={styles.label}>{label}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: { padding: 16, borderRadius: 8, backgroundColor: '#007AFF' },
  webCursor: { cursor: 'pointer' } as any, // web-only style
  pressed: { opacity: 0.7 },
  label: { color: '#fff', fontWeight: '600' },
});

Revisions (0)

No revisions yet.