How to use React and TailwindCSS in Chrome Extension Content Scripts
Recently, I've grown fond of Tailwind CSS's utility-first approach to writing CSS. Naturally, I wanted to incorporate it into browser extension development as well.
Everything was going smoothly until I encountered content scripts, where it all stopped working. Hence, this article aims to help solve this issue.
Problem description
Content scripts are JavaScript files that run in the context of web pages. They can read and modify the DOM of web pages the browser visits. However, they are isolated from the rest of the extension.
As a result, there will be some differences in how we want to use tailwindcss in our content scripts, as well as this issue
Style Isolation: The styles defined in the content script are not isolated from the styles of the original page. This can lead to conflicts and unintended side effects.
Solution
After research and experimentation, I've found an effective method to solve this problem:
1. Initialization project
I chose guocaoyi/create-chrome-ext for scaffolding. Although I haven't tried it, I believe that crxjs would also benefit from the below solution.
npx create-chrome-ext@latest
2. Install dependencies
First, we need to install the scaffold dependencies:
npm install
Then install tailwindcss dependencies (Refer to this official document)
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
3. Tailwindcss important configurations
After the initialization in the previous step, you'll get a tailwind.config.ts
file, be sure to configure the content
attribute in it
It is used to specify which files tailwindcss should look for class names in to generate the appropriate CSS.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./*.html",
"./src/**/*.{js,jsx,ts,tsx}"
],
theme: {
extend: {},
},
plugins: [],
}
4. Add Tailwind to your PostCSS configuration
Add tailwindcss
and autoprefixer
to your postcss.config.js
file, or wherever PostCSS is configured in your project.
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
5. Start injecting styles into content scripts
Create a file named index.css
containing the basic TailwindCSS directives in the src/contentScript
directory.
@tailwind base;
@tailwind components;
@tailwind utilities;
Change the name of the src/contentScript/index.ts
file tosrc/contentScript/index.tsx
, and import the index.css
file in it.
import css from './index.css?inline'
...
...
createRoot(containerDomVar).render(
<React.StrictMode>
<style type="text/css">{css}</style>
<App />
</React.StrictMode>,
)
6. Enjoy tailwindcss in content scripts
- Start the development service with the command
npm run dev
- Access chrome://extensions/
- Turn on developer mode
- Click 'load unpacked', and select
build
directory
Conclusion
By following these steps, we've successfully integrated React and TailwindCSS in a Chrome extension's content script, overcoming the challenges of style isolation and efficient CSS management in this unique environment.
index.tsx
full example like below
import React from 'react'
import { createRoot } from 'react-dom/client'
// 1. Import the css file
import css from './index.css?inline'
// import appCss from './app.css?inline'
function App() {
return (
<>
{/* You can also import a separate and isolated app css file like below,*/}
{/* without affecting the css style of the original page */}
{/* <style type="text/css">{appCss}</style> */}
<h1 className="text-red-500">Hello world!</h1>
</>
)
}
const onLoaded = () => {
const root = document.createElement('div')
document.body.prepend(root)
const shadowRoot = root.attachShadow({ mode: 'open' })
const renderIn = document.createElement('div')
shadowRoot.appendChild(renderIn)
createRoot(renderIn).render(
<React.StrictMode>
// 2. Inject the css file
<style type="text/css">{css}</style>
<App />
</React.StrictMode>,
)
}
if (document.readyState === 'complete') {
onLoaded()
} else {
window.addEventListener('load', () => {
onLoaded()
})
}