Chrome Extension Tailwind CSS — Developer Guide

3 min read

Tailwind CSS for Chrome Extensions

Tailwind CSS brings utility-first styling to Chrome extension development, offering rapid UI with minimal CSS. This guide covers integrating Tailwind into extension contexts while handling unique browser extension constraints.

Setting Up Tailwind

Install and initialize:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Configure tailwind.config.js:

module.exports = {
  content: [
    "./src/**/*.{html,js,ts,jsx,tsx}",
    "./popup/**/*.{html,js,ts,jsx,tsx}",
    "./options/**/*.{html,js,ts,jsx,tsx}",
  ],
  theme: { extend: {} },
  plugins: [],
}

Popup and options pages run in privileged extension contexts, making Tailwind setup straightforward. These pages behave like standard web pages without page style interference.

<div class="w-80 p-4 bg-white dark:bg-gray-900">
  <h1 class="text-lg font-semibold">Extension</h1>
  <button class="mt-2 px-4 py-2 bg-blue-600 text-white rounded">Click Me</button>
</div>

Content Scripts with Shadow DOM

Content scripts face a challenge: injected styles leak into the host page. Shadow DOM with adoptedStyleSheets provides isolation.

Create a shadow DOM wrapper:

const host = document.createElement('div');
host.id = 'my-extension-root';
document.body.appendChild(host);
const shadow = host.attachShadow({ mode: 'open' });

Inject styles:

import styles from './tailwind.css?inline';
const styleSheet = new CSSStyleSheet();
styleSheet.replaceSync(styles);
shadow.adoptedStyleSheets = [styleSheet];
shadow.innerHTML = `<div class="p-4 bg-white rounded">Action</div>`;

This keeps your Tailwind styles isolated from page CSS.

Using shadcn/ui Components

shadcn/ui provides accessible components built on Radix UI. Install dependencies:

npm install tailwindcss-animate class-variance-authority clsx tailwind-merge

Configure tailwind.config.js:

module.exports = {
  darkMode: ['class'],
  content: ['./src/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
  plugins: [require('tailwindcss-animate')],
}

Use components:

import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';

export function ExtensionPopup() {
  return (
    <Card className="w-72 p-4">
      <h2 className="text-xl font-bold">My Extension</h2>
      <Button className="w-full">Get Started</Button>
    </Card>
  );
}

Preventing Style Conflicts

Use a scoped prefix to avoid collisions:

module.exports = { prefix: 'ext-' }

Apply prefixed classes: <div class="ext-flex ext-items-center">.

Build Size Optimization

Extensions demand aggressive optimization:

export default {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
    cssnano({ preset: ['default', { discardComments: { removeAll: true } }] }),
  ],
}

This removes unused styles and keeps your extension package lean.

Extension-Specific Configuration

Popups max out around 400x600 pixels. Configure Tailwind:

module.exports = {
  theme: {
    extend: {
      maxWidth: { popup: '360px' },
      maxHeight: { popup: '600px' },
    },
  },
}

Use these constraints in your popup layout for responsive designs within extension viewport limits.

For more extension development patterns and tools, explore the resources at zovo.one.

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.