React
Build browser extension UIs with React using the default Extension.js pipeline.
Extension.js detects React from your project dependencies and configures JSX/TSX transforms, React aliases, and development refresh integration automatically.
When React is a good fit
- You are building rich UI surfaces like popup, options, sidebar, or new tab.
- You want component reuse across extension pages and content-script UI mounts.
- You already use React in web projects and want the same development model in extensions.
Template examples
new-react

Build a React new-tab experience with a ready-to-run project structure.
npx extension@latest create my-extension --template=new-react
Repository: extension-js/examples/new-react
content-react

Inject React UI into existing pages with a content-script-first setup.
npx extension@latest create my-extension --template=content-react
Repository: extension-js/examples/content-react
Usage with an existing extension
If you want to add React to an existing extension:
Installation
Install React runtime dependencies:
npm install react react-dom
If you use TypeScript, also install React type packages:
npm install -D @types/react @types/react-dom
Configuration
Common React file patterns:
- JavaScript:
*.jsx
- TypeScript:
*.tsx
Development behavior
In development mode, Extension.js enables React refresh integration when React is detected.
react-refresh and @rspack/plugin-react-refresh are used for refresh behavior.
- If optional refresh dependencies are missing, Extension.js installs them and asks for a restart.
- React aliases are applied to help keep a single React/runtime instance in your bundle.
Usage examples
In a new tab extension
Example page entry:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Extension</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this extension.</noscript>
<div id="root"></div>
</body>
<script src="./index.tsx"></script>
</html>
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
export default function App() {
return <h1>Hello, Extension!</h1>;
}
In a content_script file
For content scripts, render React into an injected root element:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./content.css";
const rootDiv = document.createElement("div");
rootDiv.id = "extension-root";
document.body.appendChild(rootDiv);
const root = ReactDOM.createRoot(rootDiv);
root.render(<App />);
Next steps
Video walkthrough
