React Native in the browser

How the phone-frame demo on the homepage works — a real React Native app compiled to web and embedded in an iframe.

Summary

The homepage embeds a real @daltonr/pathwrite-react-native app running inside a CSS phone frame. It is not a mockup or a separate web implementation — it is the same React Native source code that runs on iOS and Android, compiled to a browser-compatible bundle using Expo Web and react-native-web.

How Expo Web works

react-native-web provides browser equivalents for every core React Native primitive:

When Expo bundles for web it aliases react-nativereact-native-web, so the app and every library it imports (including @daltonr/pathwrite-react-native) transparently pick up the web implementations with no code changes.

Building the web bundle

From the showcase app directory:

npx expo export --platform web

This produces a static dist/ folder — an index.html and a single JS bundle. Because the app is served from a subdirectory on this site, the baseUrl must be set so asset paths resolve correctly:

// app.json
{
  "expo": {
    "experiments": {
      "baseUrl": "/apps/react-native-demos/demo-rn-showcase/dist"
    }
  }
}

Without this, Expo emits absolute paths like /_expo/static/js/web/index.js which resolve to the site root instead of the subdirectory.

Embedding in the page

The static bundle is served as a standalone page and embedded in an <iframe> inside a CSS phone frame:

<div class="phone-frame">
  <div class="phone-frame__screen">
    <iframe src="apps/react-native-demos/demo-rn-showcase/dist/"
            title="React Native showcase"></iframe>
  </div>
</div>

The phone shape is pure CSS — rounded corners, a dark bezel, a notch bar, and a box-shadow stack to give depth. No images or icon fonts required.

The Pathwrite adapter

The showcase uses @daltonr/pathwrite-react-native exactly as it would on a real device. PathShell renders its step content inside a ScrollView with KeyboardAvoidingView, and the stepper and navigation buttons use View, Text, and Pressable. All of that maps to DOM elements via react-native-web at build time — the adapter itself has no web-specific code.

import { PathShell } from "@daltonr/pathwrite-react-native";

export default function App() {
  return (
    <PathShell
      path={myPath}
      initialData={INITIAL_DATA}
      onComplete={handleComplete}
      steps={{ welcome: <WelcomeStep />, ... }}
    />
  );
}

Limitations

← Back to homepage