article

Building a Chrome Extension With React: Lessons Learned

October 10, 2025

Putting React inside a Chrome extension sounds simple — it’s just a web app in a popup, right? Mostly, but the extension environment has rules that trip up anyone treating it like a normal React project. A few lessons save a lot of pain.

The popup is not a long-lived app

It mounts when the user clicks the icon and is destroyed the moment they click away. Any state in the component is gone. So never rely on in-memory state to persist — anything that must survive a close has to live in chrome.storage, not React state. Treat the popup as a view that reads from and writes to storage.

Mind the CSP and the separate worlds

Manifest V3’s Content Security Policy bans inline scripts and eval. Some bundler defaults violate this, so build the extension with a setup that outputs CSP-safe bundles and test the packed build early — what runs with the dev server may be rejected when packed.

Understand the pieces, too. The popup, the background service worker, and content scripts are separate worlds that can’t share memory; they communicate through message passing. And the service worker isn’t persistent — it spins up to handle events and shuts down, so don’t keep important state only in its memory.

Build around storage for persistence and messages for communication, and React in an extension becomes pleasant instead of mysterious.