30 May 2023
Jozef Hruška's profile photo, Webscope.io
Jozef Hruška

Building modern browser extensions with Vite and Tailwind CSS

an image featuring Vite and Tailwind CSS logos and illustrating how they can be used together to build modern browser extensions
Browser extensions have become an integral part of our lives. We use extensions to customize browsers to our liking, whether we need to add a missing functionality or tweak their looks.
Essentially, extensions are just autonomous web pages browsers render in popup windows. Using all the goodies from traditional web development like TypeScript, Tailwind, or Vite should be easy, right? Well, yes, but it might be tricky to set up, especially when building a cross-browser extension or you want to use specific features such as HMR.
Thankfully you're just one of many struggling with this, and already existing solutions make this process much more manageable. This article will give you insight into a straightforward way of building cross-browser extensions using the latest frontend tech stack.

Setting up the browser extension

I recommend setting up the development environment with the Vite plugin @samrum/vite-plugin-web-extension. This plugin solves compatibility issues you would typically have to deal with yourself. To be precise, the plugin allows you to:
  • Quickly bootstrap Manifest V2 and V3 browser extensions.
  • Build the extension with ES modules.
  • Import and use static assets as you would in a regular Vite application.
  • Use HMR and Fast Refresh.
The plugin also has an init command, which will let you choose the Manifest version, whether or not you want to use TypeScript and the framework of your choice (React, Preact, Vue, Svelte, or no framework at all).
1npm init @samrum/vite-plugin-web-extension@latest
What Manifest version you should choose depends mainly on your requirements.
Manifest V2 is tried and tested and has looser limitations than newer Manifest V3. However, the Manifest V2 is approaching its end of life, although the day when the Chrome Web Store will stop accepting Manifest V2 extensions has been postponed, and no new date has been set yet.
On the other hand, Manifest V3 has significantly changed what and how extensions can behave. The support on Chromium-based browsers is quite good already, but other browser families support Manifest V3 only partially or not at all. Firefox, for example, publicly states the work is still in progress and subject to change.

Do you need a reliable partner in tech for your next project?

Adding useful dependencies

Depending on whether you are building a cross-browser extension, I recommend installing the webextension-polyfill package. This package will let you use the exported browser API, which follows the standards set by the W3 Browser Extensions group. Theoretically, this will allow you to use one API that works on Chrome, Firefox, and possibly other browser families. However, be aware it's not a 1:1 replacement for the chrome API as it lacks support for some APIs only available on Chrome.
1npm i webextension-polyfill
If you don't need cross-browser support and have chosen to use TypeScript, I recommend installing the @types/chrome package, which will provide you with types for the chrome API.
1npm i --save-dev @types/chrome
The last helpful dependency I'd like to recommend, although a bit more specialized, is the user-agent-data-types. It extends the navigator interface type with a new navigator.userAgentData API, which lets you query information about the user-agent (browser, platform).
1npm i --save-dev user-agent-data-types

Adding Tailwind CSS

To add Tailwind, follow their installation guide. I recommend using PostCSS as the experience felt the most seamless to me. Once you are done with the installation, you must import the stylesheets to the popup and/or options views. You can either import it in the JS main JS file or directly in HTML. For example, this is how you could import it in the popup UI's App.tsx.
1import PageContent from '~/components/PageContent';
2import '../../styles.css'; // 👈 A CSS file containing `@tailwind` directives
4function App() {
5  return (
6    <main>
7      <PageContent>Popup</PageContent>
8    </main>
9  );
12export default App;


The experience of developing a web application is much less cumbersome than it used to be 5 or 10 years ago. We've grown used to modern JavaScript frameworks like React or Vue, build tools like Vite, or CSS frameworks like Tailwind. Although the environment of browser extensions is somewhat special, there are existing tools that allow us to use all these tools to build modern browser extensions quickly.
A complete example built around vite-plugin-web-extension with React, Taiwind CSS, and other before-mentioned packages is available at https://github.com/jozefhruska/browser-extension-example.
A big shoutout and thanks go to Ruben Medina (@samrum) and all the contributors for making this possible!
Share post

Let’s stay connected

Do you want the latest and greatest from our blog straight to your inbox? Chuck us your email address and get informed.
You can unsubscribe any time. For more details, review our privacy policy