Building Browser Extensions with React - That Don't Break Browsers

This ad is not shown to multipass and full ticket holders
React Summit
React Summit 2026
June 11 - 15, 2026
Amsterdam & Online
The biggest React conference worldwide
Learn More
In partnership with Focus Reactive
Upcoming event
React Summit 2026
React Summit 2026
June 11 - 15, 2026. Amsterdam & Online
Learn more
Bookmark
Rate this content

Browser extensions face unique challenges that web apps never encounter - from Manifest V3 constraints to cross-script communication. After 4+ years building production ready browser extensions in React, I'll share the architecture patterns, performance optimizations, and debugging techniques that prevent extensions from breaking user browsing experience. You'll learn battle-tested solutions for state management across tabs, inter-script communication, and the performance pitfalls that can kill your extension's adoption.

This talk has been presented at React Summit US 2025, check out the latest edition of this React Conference.

FAQ

The speaker is Jonny Fekete, who has over five years of experience working with production-ready web extensions and contributes to open-source projects in this field.

Jonny Fekete's presentation focuses on how to build web extensions using React that do not break browsers.

Web extensions are essentially zip files that include a manifest.json file, which describes permissions, the extension's name, description, version number, and other configurations.

Chrome transitioned from manifest.v2 to manifest.v3, introducing a more streamlined and safe version of manifest.json with more restrictive permissions but greater power for end users.

The recommended framework is WXT, which is described as Next.js for extensions and comes with features like fast hot module reloading and React support.

Challenges include state persistence, multi-tab state management, CSS collision, communication between web pages and extensions, authentication, and memory leak issues.

Using Shadow DOM and custom web components to wrap React bundles can prevent CSS collision by isolating styles from the underlying web page.

Web extensions use the sendMessage API to communicate between different parts like popups and background scripts. Chrome.runtime.sendMessage and Chrome.runtime.onMessage.addListener are used for sending and receiving messages.

Cleanup is critical for production stability, and developers should use throttling and debouncing to manage background script load effectively.

Jonny Fekete offers a free YouTube tutorial series at webextensiontutorial.com.

Johnny Fekete
Johnny Fekete
20 min
21 Nov, 2025

Comments

Sign in or register to post your comment.
Video Summary and Transcription
Jonny Fekete discusses building web extensions with React, the simplicity of manifest.json, the shift from manifest.v2 to manifest.v3 in Chrome, and the impact on functionalities like persistent background scripts and access restrictions. The transition to manifest.v3 for web extensions, the siloed contexts of web extensions, and the use of sendMessage API for communication between different contexts. Challenges in web extension development, complexities of setting up custom configurations, and the modern approach with the WXT framework for easier development and state persistence. Challenges in state persistence and data storage in web extensions, including local, session, and event sync storage methods. Managing multiple tabs' state and data storage with consideration for tab IDs to prevent memory leaks. Consider using storage over Redux for better debugging and architecture. Address CSS collision with Shadow DOM and custom web components to isolate styles from the underlying web page. Utilize background script for throttling and debouncing, efficient storage utilization, and the WXT framework for ease of development and communication.

1. Building Web Extensions with React

Short description:

Jonny Fekete discusses building web extensions with React, the simplicity of manifest.json, the shift from manifest.v2 to manifest.v3 in Chrome, and the impact on functionalities like persistent background scripts and access restrictions.

Welcome, everyone. My name is Jonny Fekete, and I will talk about how to build web extensions with React that do not break browsers. So let's get started. I'm sure all of you are very familiar with working with React since this is a React conference. However, have you ever tried building a web extension using React? I can tell you it's not as easy as you're used to with your own web application. Why am I eligible to talk about the subject? Well, I've been working with production-ready web extensions for more than five years now, and I believe I faced a lot of challenges that really pushed the limits of what's possible with web extensions. Plus, I am contributing to some of the open-source communities projects in this field. And more than everything, I have a YouTube tutorial series called webextensiontutorial.com where you can learn for free about how to create web extensions.

But what are web extensions, you might ask? Well, they are just zip files, really, with manifest.json. That's all it takes to create a web extension. The manifest.json file is a simple JSON that describes what permissions are required, what is the name of the extension, the description, version number, and a lot of other configurations. And, basically, that's it. If you create a zip file with this, you can immediately start debugging and creating new extensions. However, you might have heard that a couple of years ago, Chrome went from manifest.v2 to manifest.v3. They introduced a more streamlined and safe version of manifest.json. In v2, you had persistent background scripts. You had full DOM access from the background. You could import React everywhere, even in the background script. You had access to the local storage and the session storage. And there were just a lot of APIs that were inconsistent.

And manifest.v3, it solves all these problems. It is a lot more restrictive on the extension side, but it gives a lot more power for the end users. And some examples why things are different. The background is now a service worker, so you can't really keep persistent background scripts. The scripts can fall asleep or die and then wake up based on certain triggers. You don't have local storage access. You have different storages that are web extension specific. All the APIs are now async and promise-based. And you have import restrictions, so you can't really import React into your background scripts. If you remember a few years ago, the community was very loud about this because these restrictions made it difficult for ad blockers to function and people were blaming Google for introducing these restrictions.

2. Web Extension Contexts and Communication

Short description:

The transition to manifest.v3 for web extensions, the siloed contexts of web extensions, and the use of sendMessage API for communication between different contexts.

But as you might have noticed, the world didn't end. There are still ad blockers, so things got figured out. And now we have manifest.v3. With the web extensions, we are talking about isolated contexts because a web extension has a popup. Many of them have popups when you click on the icon. Here is an example of Grammarly. Then it has a context content script when it injects some widget or some functionality to the web page that is open in the tab. And then it has background scripts, which are like service workers. They do not have the access to the open tab. And the contents of the background script don't live forever. They are not persisted. You might be able to trigger them through certain events such as when a message arrives or when the user changes a tab, some cookies change. The background scripts can listen to a lot of events and then when these events happen, they can do the logic and then die or go back to sleep.

However, one important thing to point out here is that these contexts are siloed. They are not living in the same place. You have different files for them. You are initiating React if you're using React in all these locations where you're using it except the background script because there you cannot. One of the biggest issues with web extensions is therefore the communication challenge because how do you tell from the popup something to the background script or something to the tab that is open? Well, there is an API for that. It's called sendMessage. And here's an example from popup to background. You can send Chrome.runtime.sendMessage with any payload. In this case, it's action getData, but it can be any object that can be passed to JSON stringify.

And the background script can listen to messages. As I told you, it's normally not live, but Chrome.runtime.onMessage.addListener is a way to listen to messages. And in our case, we are checking if the message.action is getData. And if it's getData, do something and sendResponse. SendResponse is an optional parameter. It's a callback function, but this is super useful because this way we can send message from one place to another and wait until the response came back. This works perfectly when the extension-owned scripts are targeted, such as the background script or a popup or the sidebar if you use a custom web page, a custom options page. However, when you are targeting the content script, which is living inside the contents of the open tab, this is a little bit different, nothing major, but you have to use Chrome.tabs.sendMessage.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Install Nothing: App UIs With Native Browser APIs
JSNation 2024JSNation 2024
31 min
Install Nothing: App UIs With Native Browser APIs
Top Content
This Talk introduces real demos using HTML, CSS, and JavaScript to showcase new or underutilized browser APIs, with ship scores provided for each API. The dialogue element allows for the creation of modals with minimal JavaScript and is supported by 96% of browsers. The web animations API is a simple and well-supported solution for creating animations, while the view transitions API offers easy animation workarounds without CSS. The scroll snap API allows for swipers without JavaScript, providing a smooth scrolling experience.
Pushing the Limits of Video Encoding in Browsers With WebCodecs
JSNation 2023JSNation 2023
25 min
Pushing the Limits of Video Encoding in Browsers With WebCodecs
Top Content
Watch video: Pushing the Limits of Video Encoding in Browsers With WebCodecs
This Talk explores the challenges and solutions in video encoding with web codecs. It discusses drawing and recording video on the web, capturing and encoding video frames, and introduces the WebCodecs API. The Talk also covers configuring the video encoder, understanding codecs and containers, and the video encoding process with muxing using ffmpeg. The speaker shares their experience in building a video editing tool on the browser and showcases Slantit, a tool for making product videos.
WebHID API: Control Everything via USB
JSNation 2022JSNation 2022
23 min
WebHID API: Control Everything via USB
Today's Talk introduces the webHID API, which allows developers to control real devices from the browser via USB. The HID interface, including keyboards, mice, and gamepads, is explored. The Talk covers device enumeration, input reports, feature reports, and output reports. The use of HID in the browser, especially in Chrome, is highlighted. Various demos showcase working with different devices, including a DualShock controller, microphone, gamepad, and Stream Deck drum pad. The Talk concludes with recommendations and resources for further exploration.
Automate the Browser With Workers Browser Rendering API
JSNation 2024JSNation 2024
20 min
Automate the Browser With Workers Browser Rendering API
The Talk discusses browser automation using the Worker's Browser Rendering API, which allows tasks like navigating websites, taking screenshots, and creating PDFs. Cloudflare integrated Puppeteer with their workers to automate browser tasks, and their browser rendering API combines remote browser isolation with Puppeteer. Use cases for the API include taking screenshots, generating PDFs, automating web applications, and gathering performance metrics. The Talk also covers extending sessions and performance metrics using Durable Objects. Thank you for attending!
Visualising Front-End Performance Bottlenecks
React Summit 2020React Summit 2020
34 min
Visualising Front-End Performance Bottlenecks
React's web-based tools allow for independent learning. Dazzone, a sports streaming service, faces challenges with low memory and CPU targets. Measuring, analyzing, and fixing performance issues is crucial. Virtualization improves rendering efficiency and performance. The application is now much faster with significantly less jank.
MIDI in the Browser... Let's Rock the Web!
JSNation 2022JSNation 2022
28 min
MIDI in the Browser... Let's Rock the Web!
MIDI is a versatile communication protocol that extends beyond music and opens up exciting possibilities. The Web MIDI API allows remote access to synths and sound modules from web browsers, enabling various projects like music education systems and web audio-based instruments. Developers can connect and use MIDI devices easily, and the Web MIDI API provides raw MIDI messages without semantics. The WebMidi.js library simplifies working with the Web MIDI API and offers a user-friendly interface for musicians and web developers. MIDI on the web has generated significant interest, with potential for commercial growth and endless possibilities for web developers.

Workshops on related topic

Writing Universal Modules for Deno, Node and the Browser
Node Congress 2022Node Congress 2022
57 min
Writing Universal Modules for Deno, Node and the Browser
Workshop
Luca Casonato
Luca Casonato
This workshop will walk you through writing a module in TypeScript that can be consumed users of Deno, Node and the browsers. I will explain how to set up formatting, linting and testing in Deno, and then how to publish your module to deno.land/x and npm. We’ll start out with a quick introduction to what Deno is.