Featured image of post Use React Js in Electron Project

Use React Js in Electron Project

Electron is still a great way to build cross-platform desktop apps if you have web development experience. Here’s how to quickly add React to an Electron app using Vite and Electron Forge.

How to use React on Electron app

If you’ve spun up a fresh Electron app with Electron Forge + Vite and want React, here’s the quickest way I’d do it (plus a couple gotchas I ran into).

TL;DR

  • Install React and the Vite React plugin.
  • Put the React plugin in the renderer Vite config (not the main process).
  • Use a .tsx entry for the renderer.
  • Point Forge to your renderer Vite config.

1. Install React

1
2
npm install react react-dom
npm install -D @vitejs/plugin-react

2. Set up the renderer Vite config

Create a renderer config dedicated to the UI and enable the React plugin.

vite.renderer.config.mts

1
2
3
4
5
6
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
});

Make sure your Forge plugin points at this file:

forge.config.ts (renderer section)

1
2
3
4
5
6
renderer: [
  {
    name: 'main_window',
    config: 'vite.renderer.config.mts',
  },
],

Tip: Keep React plugin out of the main process config. It’s only for the renderer.

3. Fix ESM/require config issues (if any)

If you previously had @vitejs/plugin-react inside vite.main.config.ts, you’ll likely see an “ESM file cannot be loaded by require” error. Move that plugin to the renderer config and keep your main config minimal (or rename it to .mts if you really need ESM).

Example minimal main config:

vite.main.config.mts

1
2
3
4
5
import { defineConfig } from "vite";

export default defineConfig({
  // Keep this simple; no React plugin here
});

4. Use a TSX renderer entry

Create a React entry point and render your app.

src/renderer/index.tsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./index.css"; // keep or remove if not using styles yet

const container = document.getElementById("root")!;
const root = createRoot(container);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

src/App.tsx

1
2
3
4
5
6
7
8
9
import React from "react";

export default function App() {
  return (
    <div style={{ padding: 24 }}>
      <h1>Hello from React in Electron</h1>
    </div>
  );
}

5. Hook the HTML to the renderer entry

Your Vite dev HTML should point to the renderer entry.

index.html (project root)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>My Electron + React App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/renderer/index.tsx"></script>
  </body>
</html>

6. TypeScript JSX setting

Make sure your tsconfig supports JSX:

tsconfig.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "strict": true,
    "moduleResolution": "node",
    "target": "ES2020",
    "module": "ESNext",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src", "index.html"]
}

7. Start it up

That’s it! Now let’s run the app:

1
npm start

Troubleshooting

If the window opens but React isn’t rendering, open DevTools and make sure:

  • The HTML has a div#root.
  • The script tag points to /src/renderer/index.tsx.
  • No JSX is inside .ts files (use .tsx).
Built with Hugo
Theme Stack designed by Jimmy