DEV Community

Cover image for From Mobile to Browser: A Guide to React Native for Web
Debajit Mallick
Debajit Mallick

Posted on

From Mobile to Browser: A Guide to React Native for Web

Introduction

React Native has a quote: "write once, run everywhere." But honestly, I always felt like something was missing. Sure, we could target iOS and Android, but what about the web? That's where millions of users spend their time every day. Then I stumbled upon React Native for Web, and let me tell you – it was a game-changer. Suddenly, that same codebase I'd been pouring my heart into for mobile apps could reach web users too. If you already have a react-native app then you can convert your app code easily to web with minimal changes.

What Exactly is React Native for Web?

Think of React Native for Web as your friendly translator. It takes all those React Native components you know and love – View, Text, Image – and magically transforms them into their web equivalents. Your View becomes a div, your Text becomes a span or p element. Specifically, the span element is used for text that is part of a larger text flow (inline), while the p element is used for standalone paragraphs. , and your Image becomes an img tag. It's like having a universal language for UI development.

The best part? If you're already using Expo, web support is baked right in.

Advantages of using React-Native for web:

Look, I've been around the block. I've built separate React apps for web and React Native apps for mobile. I've felt the pain of duplicating logic, styling components twice, and keeping everything in sync. Here's why React Native for Web changed everything for me:

  • Zero Configuration Stress: Expo handles all the heavy lifting. I can focus on building features instead of fighting build tools.
  • My Code Gets Reused: Not just the business logic – the entire UI components work across platforms. That custom button I spent hours perfecting? It looks and works the same everywhere.
  • SEO That Actually Works: With App Router, I get proper URLs and SEO-friendly routing.
  • Time is Money: Instead of juggling multiple codebases, I can ship features faster as the codebase is shared.

Getting Started

First, let's create our project. To create the project, I am using Expo. Here are the commands to create the basic boilerplate using Expo:

npx create-expo-app my-app
cd my-app
Enter fullscreen mode Exit fullscreen mode

Now, fire up the development server:

npx expo start
Enter fullscreen mode Exit fullscreen mode

Press w in your terminal, and watch your React Native app open in your browser.

Explore App Router

Expo’s App Router is like Next.js for React Native – filesystem-based routing that works out of the box. Just create folders and files, and Expo handles the routes automatically.

  • In the app/ directory (this already exists in new Expo projects):

app/
├── index.tsx // maps to ‘/’
├── about/
│ ├── index.tsx // maps to ‘/about’
│ └── _layout.tsx // optional shared layout for /about pages

  • Let’s create our home page:
// app/index.tsx
import { View, Text, Pressable } from 'react-native';
import { Link } from 'expo-router';

export default function Home() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 24 }}>Welcome to React Native Web with Expo!</Text>
      <Link href="/about">
        <Pressable>
          <Text style={{ color: 'blue', marginTop: 20 }}>Go to About Page</Text>
        </Pressable>
      </Link>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • About page:
// app/about/index.tsx
import { View, Text, Pressable } from 'react-native';
import { Link } from 'expo-router';

export default function About() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 24 }}>This is the About Page</Text>
      <Link href="/">
        <Pressable>
          <Text style={{ color: 'blue', marginTop: 20 }}>Back to Home</Text>
        </Pressable>
      </Link>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

✅ (Optional) Add _layout.tsx for nested layouts if you want shared headers, footers, or other UI elements across pages.

✅ Run your project on web:

npx expo start
Enter fullscreen mode Exit fullscreen mode

Press w to open in your browser. Navigate to /about and watch the webapp to render.

Handling Flatlist

FlatList on web can be tricky, but when you get it right, it's amazing:

import React from 'react';
import { FlatList, Text, View } from 'react-native';

const DATA = [
  { id: '1', title: 'First item' },
  { id: '2', title: 'Second item' },
  { id: '3', title: 'Third item' },
];

export default function MyList() {
  const renderItem = ({ item }) => (
    <View style={{ 
      padding: 10, 
      borderBottomWidth: 1, 
      borderColor: '#ccc' 
    }}>
      <Text>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={DATA}
      renderItem={renderItem}
      keyExtractor={item => item.id}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

Handling API Calls

For any real world webapp we need to handle API calls. To handle API calls in react-native and render elements in UI:

import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';

export default function DataFetcher() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => {
        setData(json);
        setLoading(false);
      })
      .catch(error => {
        console.error('Something went wrong! Error: ', error);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <ActivityIndicator size="large" color="#0000ff" />;
  }

  return (
    <View>
      {data.slice(0, 5).map(item => (
        <Text key={item.id}>{item.title}</Text>
      ))}
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Handling Responsive Design

Here's how we can handle responsive design for web for different device width:

import { View, Text, useWindowDimensions } from 'react-native';

export default function ResponsiveComponent() {
  const { width } = useWindowDimensions();

  // to check the device screen is desktop or mobile
  const isDesktop = width > 600;

  return (
    <View style={{
      backgroundColor: isDesktop ? 'lightblue' : 'lightgrey',
      padding: 20,
    }}>
      <Text style={{ 
        fontSize: isDesktop ? 24 : 16,
        textAlign: isDesktop ? 'left' : 'center'
      }}>
        This text adapts to your screen size
      </Text>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Handling code specific for web:

To handle the code specific for web, we can use the Platform API from React Native. From the OS, we can do a check if it's a web browser or not. Here is an example code:

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

export default function RenderOnWeb() {
  if (Platform.OS === 'web') {
    return (
      <View style={{ padding: 20, backgroundColor: '#f0f0f0' }}>
        <Text style={{ fontSize: 18 }}>This is rendered only on Web</Text>
      </View>
    );
  }

  // Optionally render something else for mobile
  return (
    <View style={{ padding: 20, backgroundColor: '#e0ffe0' }}>
      <Text style={{ fontSize: 18 }}>This is rendered on Mobile 📱</Text>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

React Native for Web helps us to convert our existing mobile app code to web without creating a new project. It's about building once and deploying everywhere, without sacrificing quality or performance. At the end of the day no library or framework is good or bad. It's all about the use case and tradeoffs. Start with something simple – maybe just a landing page or a basic dashboard, and then move in to some more complex apps. If you like this blog and want to learn more about Frontend Development and Software Engineering, you can follow me on Dev.to.

Top comments (0)