UI Development & Web Preview

Build high-performance web frontends for 5M Phone with React 18, TypeScript, Tailwind CSS, and Vite.


Fast Local Development in Browser

The official template lets you build and test your app directly in your desktop browser without opening FiveM:

Shell
cd 5M_CustomApp/ui
npm install
npm run dev

Vite will start a local development server at http://localhost:5173/. Open this link in Google Chrome.

Mock Bridge for Browser Testing

When running in browser outside of FiveM, phoneBridge.ts falls back to simulated data so your UI never crashes:

TypeScript
// ui/src/lib/phoneBridge.ts detects when window.GetParentResourceName is undefined
// and returns mock player data, mock coordinates, and simulated dark mode.

Live In-Game HMR (Hot Module Replacement)

While developing inside FiveM, you can stream your live Vite development server directly into the in-game phone screen:

  1. Start the Vite dev server on your machine:

    Shell
    cd ui
    npm run dev
  2. In 5M_CustomApp/config.lua, set:

    Lua
    Config.UiPath = 'http://localhost:5173/'
  3. Restart 5M_CustomApp in server console: restart 5M_CustomApp.

  4. Open 5M Phone in-game. Any CSS or TSX changes you save in VS Code will update instantaneously on the in-game phone screen without reloading!


Building for Production

When you are ready to deploy your app:

Shell
cd ui
npm run build

This compiles your TypeScript and React source files into optimized, production-ready static assets in ui/dist/:

  • Bundled and minified HTML, CSS, and JS.
  • No external CDN dependencies or Node.js runtime required at FiveM runtime.

In config.lua, ensure Config.UiPath points back to the built bundle:

Lua
Config.UiPath = 'ui/dist/index.html'

Automatic Dark & Light Theme Handling

5M Phone passes the player's active theme ('light' or 'dark') into your app iframe via query parameters:

TypeScript
import { applyTheme, getPhoneBridgeMeta } from './lib/phoneBridge';

export function App() {
  const meta = getPhoneBridgeMeta();

  useEffect(() => {
    applyTheme(meta.theme);
  }, [meta.theme]);

  return (
    <div className="min-h-full bg-white text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
      {/* App Content */}
    </div>
  );
}

The applyTheme() helper sets data-theme="dark" or data-theme="light" on document.documentElement, allowing standard Tailwind dark: utility classes to activate automatically.