ย 

Build a React TailwindCSS Chrome Extension in 5 Minutes

John Braat

Jonathan Braat / November 21, 2022 โ‹… 5 min read

Learn how to build a Google Chrome web extension with React, TypeScript and TailwindCSS in less than 5 minutes. Includes a free template.

I have been building Chrome extensions for a while now.

Most notably Supatabs available in the Chrome Web Store. Supatabs is a an extension to reduce tab clutter and improve your computer's performance. By reducing the amount of open tabs you can save up to 95% of your RAM.

In this article I want to show you how you can build a production ready extension in only 5 minutes.

Start with a template

One of the byproducts of Supatabs is an extension template I built.

The template is setup and ready to go with Manifest V3, React, TailwindCSS and TypeScript. Instead of webpack I used vite for bundling. In my opinion it's easier to maintain.

Follow these steps to set up your new chrome extension:

  1. Go to the template repository
  2. Click the "Use this template" button to create your own project in your GitHub. If you aren't using GitHub just clone the repository
  3. Go back to the template repository and give it a star ๐Ÿ˜œ

Setting up the development environment

Follow these steps to start your dev environment:

  1. Change the name, displayName and description in the package.json. These properties will be used in the build step to name your extension for the store
  2. yarn install to install the dependencies
  3. yarn dev to start the development server
  4. Load the extension in Chrome:
    1. Open your Chrome browser
    2. Enter chrome://extensions in the address bar and hit enter
    3. Turn on developer mode
    4. Load unpacked extension: Use the generated dist directory in your project folder. This will be generated and updated when you use yarn dev or yarn build

That's all you need to do.

A manifest with version 3 will be generated automatically for you.

Whenever you save changes and the dev command is running, the dist directory will automatically be updated thanks to nodemon. This means you don't have to do step 4 more than once.

Implement some functionality

To get a feel for how extension development works, we will implement a simple button in the extension popup to open a specific url in new tab or focus it if it already exists in your tabstrip.

Prepare

As we won't need most of the different Chrome extension pages in the template, we will remove the irrelevant source files from the project and modify our config. This is so they won't be included in the final build.

Stop the development server and then delete the following directories including content:

  • src/pages/content/*
  • src/pages/devtools/*
  • src/pages/newtab/*
  • src/pages/options/*
  • src/pages/panel/*
  • src/pages/background/*

Then we will modify the vite.config.ts to look like the following:

vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
import makeManifest from './utils/plugins/make-manifest';

const root = resolve(__dirname, 'src');
const pagesDir = resolve(root, 'pages');
const assetsDir = resolve(root, 'assets');
const outDir = resolve(__dirname, 'dist');
const publicDir = resolve(__dirname, 'public');

export default defineConfig({
  resolve: {
    alias: {
      "@src": root,
      "@assets": assetsDir,
      "@pages": pagesDir,
    },
  },
  plugins: [react(), makeManifest()],
  publicDir,
  build: {
    outDir,
    sourcemap: process.env.__DEV__ === "true",
    rollupOptions: {
      input: {
        popup: resolve(pagesDir, 'popup', 'index.html'),
      },
      output: {
        entryFileNames: (chunk) => `src/pages/${chunk.name}/index.js`,
      },
    },
  },
});

Now we need to modify src/manifest.ts accordingly. We will remove unnecessary config params and add chrome.tabs permission to query active tabs.

src/manifest.ts
import pkg from '../package.json';
import { ManifestType } from '@src/manifest-type';

const manifest: ManifestType = {
  manifest_version: 3,
  name: pkg.displayName,
  version: pkg.version,
  description: pkg.description,
  action: {
    default_popup: 'src/pages/popup/index.html',
    default_icon: 'icon-34.png',
  },
  permissions: [ 'tabs' ],  // <-- this how you add permissions
  icons: {
    "128": 'icon-128.png',
  },
  web_accessible_resources: [
    {
      resources: ['icon-128.png', 'icon-34.png'],
      matches: [],
    },
  ],
};

export default manifest;

Implement

Once we are done with the preparation, we can restart the dev server with yarn dev.

We will now add the button to open a tab with a specific URL or focus it if it already exists. The implementation will be in React with TypeScript. We will apply styles with TailwindCSS.

src/pages/popup/Popup.tsx
import React from 'react';

export default function Popup(): JSX.Element {

  /**
   * A simple function to query the chrome.tabs api for an url
   * If a tab with the matching url was found we focus it 
   * Otherwise create the tab and focus 
   *
   * chrome.tabs docs here: https://developer.chrome.com/docs/extensions/reference/tabs/
   */
  const createOrFocus = async () => {
    const [res] = await chrome.tabs.query({ url: 'https://www.google.com/' });
    if (res?.id) {
      await chrome.tabs.update(res.id, { active: true });
    } else {
      chrome.tabs.create({ url: 'https://google.com' });
    }
  }

  // Some react code styled with TailwindCSS
  return (
    <div className="absolute top-0 left-0 right-0 bottom-0 flex justify-center items-center text-white text-center h-full p-3 bg-gray-800">
      <button
        className="font-bold text-lg px-4 py-1.5 border border-white rounded-lg hover:bg-gray-600"
        onClick={() => createOrFocus()}
      >
        Open or focus tab
      </button>

    </div>
  );
}

I won't go into the implementational details, as this is fairly simple react with a button.

This showcases how similar extension development can be to normal web development.

Publish

To publish stop the dev server and run yarn build

Now you can zip the dist folder and upload your package to the Chrome Web Store.

That's it. You just built a Chrome extension with React, TypeScript and TailwindCSS under 5 minutes.

If you liked this article and know a friend who could benefit from it as well, please consider sharing it ๐Ÿ™ If you want to get news and updates from me, subscribe to the newsletter below ๐Ÿ‘‡ or follow me on Twitter.

Related Articles