Skip to main content

React Content Scripts

CRXJS brings an authentic Vite HMR experience to content scripts. Let's add a React content script to your Chrome Extension.

Did you know?

A content script is JavaScript from a Chrome Extension that the browser executes on a designated web page. The page where the script runs is called the host page. The content script shares the DOM with the host page but has a separate JavaScript environment.

Add a content script

We declare content scripts with a list of JavaScript files and match patterns for the pages where Chrome should execute our content script. In manifest.json, create the field content_scripts with an array of objects:

manifest.json
{
// other fields...
"content_scripts": [
{
"js": ["src/content.jsx"],
"matches": ["https://www.google.com/*"]
}
]
}

Here we're telling Chrome to execute src/content.jsx on all pages that start with https://www.google.com.

Create the root element

Content scripts don't use an HTML file, so we need to create our root element and append it to the DOM before mounting our React app.

info

Vite now defaults to React v18 which uses ReactDOM.createRoot instead of previous ReactDOM.render https://reactjs.org/blog/2022/03/29/react-v18.html

src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
// this element doesn't exist
document.getElementById('root'),
)

Implementation for React 18+

src/main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from './App'

ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

Let's add that root element. Make a copy of src/main.jsx and name it src/content.jsx. Add the highlighted code.

src/content.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'

const root = document.createElement('div')
root.id = 'crx-root'
document.body.append(root)

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
root,
)

Implementation for React 18+

src/content.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";

const root = document.createElement("div");
root.id = "crx-root";
document.body.appendChild(root);

ReactDOM.createRoot(root).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

Get the right URL

info

Content scripts share the origin of the page where they run.

The browser treats the imported value logo as a URL from the host page. If the content script is running on https://google.com, the following img tag will try to load from https://google.com/logo.svg.

src/App.jsx
<img
src={logo}
className='App-logo'
alt='logo'
/>

We need to get a URL with our extension id for static assets like images. Use the getURL() method to get the extension url for our logo:

src/App.jsx
<img
src={chrome.runtime.getURL(logo)}
className='App-logo'
alt='logo'
/>

Now our content script is ready for action! Let's try it out in the next section.