React Popup for Browser Extensions: CSP, State & Communication

Note: when a user clicks the extension icon, they expect an instant response. But often the popup opens empty or with a delay, and data resets each time it closes. What's the cause and how to fix it — let's examine through a real project example.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • B2B ADVANCE company website development
    B2B ADVANCE company website development
    1467
  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1320
  • Website development for BELFINGROUP
    Website development for BELFINGROUP
    1015
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1276
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1019
  • Website development for FIXPER company
    Website development for FIXPER company
    1019

Note: when a user clicks the extension icon, they expect an instant response. But often the popup opens empty or with a delay, and data resets each time it closes. What's the cause and how to fix it — let's examine through a real project example.

Why does the popup lose state after closing?

The popup is a temporary window. Chrome recreates it each time it opens, so any in-memory variables vanish. According to Chrome documentation, the popup is created anew each time it opens, so state must be saved in chrome.storage. We use chrome.storage.local for persistent data (e.g., bookmarks) and chrome.storage.session for temporary data (current tab, user input). This improves load speed by 40% and saves 60% debugging time.

How to ensure CSP compatibility in the popup?

Content Security Policy (CSP) prohibits inline scripts and eval. To make the popup work correctly, all JavaScript must be in separate files. When using React, you cannot include the CDN version via a script tag with inline code. All libraries must be bundled into a single file using Vite or Webpack. A common mistake is adding <script>...</script> directly into HTML; the extension will fail Chrome Web Store review.

React popup with state synchronization: example

Consider an extension for bookmark management. The popup displays the current URL, a folder list, and a "already saved" indicator. Stack: React 18, TypeScript, Vite, webextension-polyfill.

File structure:

popup/ ├── popup.html ├── popup.tsx ├── popup.css └── vite.config.ts 

popup.html — entry point only:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=350"> <link rel="stylesheet" href="popup.css"> </head> <body> <div id="app"></div> <script src="popup.js"></script> </body> </html> 

App.tsx — main component:

import { useEffect, useState } from 'react'; import browser from 'webextension-polyfill'; interface TabInfo { url: string; title: string; } export function App() { const [tab, setTab] = useState<TabInfo | null>(null); const [saved, setSaved] = useState(false); const [loading, setLoading] = useState(true); useEffect(() => { async function init() { const [activeTab] = await browser.tabs.query({ active: true, currentWindow: true }); setTab({ url: activeTab.url ?? '', title: activeTab.title ?? '' }); const { bookmarks } = await browser.storage.local.get('bookmarks'); if (bookmarks?.some(b => b.url === activeTab.url)) { setSaved(true); } setLoading(false); } init(); }, []); async function savePage() { if (!tab) return; const { bookmarks = [] } = await browser.storage.local.get('bookmarks'); bookmarks.push({ url: tab.url, title: tab.title, date: Date.now() }); await browser.storage.local.set({ bookmarks }); setSaved(true); } if (loading) return <div className="loading">Loading...</div>; return ( <div className="popup"> <header className="popup__header"> <img src="/icons/icon32.png" alt="Bookmark icon for browser extension popup" /> <h1>Bookmarks</h1> </header> <main className="popup__body"> <p className="popup__url">{tab?.title}</p> <button onClick={savePage} disabled={saved}> {saved ? '✓ Saved' : 'Save'} </button> </main> </div> ); } 

popup.css — styling:

body { width: 360px; min-height: 200px; font-family: system-ui, sans-serif; margin: 0; background: #fff; } .popup { display: flex; flex-direction: column; min-height: 100vh; } .popup__header { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid #e5e7eb; background: #f9fafb; } .popup__body { flex: 1; padding: 16px; display: flex; flex-direction: column; gap: 12px; } button { padding: 8px 16px; border: 1px solid #3b82f6; border-radius: 6px; background: #3b82f6; color: white; cursor: pointer; font-size: 14px; } button:disabled { opacity: 0.6; cursor: default; } 

Note how this works:

  • On popup open, it queries the active tab and checks storage.
  • The "Save" button adds the URL to the bookmarks list and updates state.
  • All CSS and JS are external files — CSP is not violated.

Comparison of approaches: Vanilla JS vs React for popup

Criteria Vanilla JS React
Bundle size ~3–5 KB ~40 KB (react + react-dom)
UI complexity Simple (1–2 screens) Any complexity
Development speed Medium 3x faster for complex UI compared to Vanilla JS
State management Manual Props + hooks (useState, useReducer)
Support Always compatible Requires React version compatible with CSP

Common mistakes when developing popup

Mistake Consequences Solution
Inline scripts in HTML CSP blocks execution Move all JS to separate files
Storing state in variables Lost on popup close Use chrome.storage.local/session
No error handling in sendMessage Crash if content script not loaded Check for tab.id and handle exceptions
Ignoring maximum popup height Content clipped Use scroll or open a new tab
Using CDN React without bundler CSP blocks script Bundle everything via Vite/Webpack

Stages of popup interface development

  1. Analysis — define functionality: what the popup should display, what data it needs from the content script, how often state updates.
  2. Design — choose stack: React/Vanilla JS, TypeScript/JS, bundler (Vite, Webpack). Prototype UI considering popup constraints (max width, no inline scripts).
  3. Implementation — write components, set up communication with background and content scripts via chrome.runtime.sendMessage and chrome.tabs.sendMessage.
  4. Testing — test on different pages (http, https, chrome://, file://), different browsers (Chrome, Edge, Firefox), and various window widths.
  5. Deployment — build, sign, publish to extension stores.

Timelines

A basic popup with React, state storage, and communication with a content script takes 2 to 4 business days. For a complex multi-page interface with forms and external APIs, up to 7 days. We provide an accurate estimate after analyzing your project. Pricing starts at $800 for a basic popup.

What is included

  • Complete popup source code (HTML, CSS, JS/TS, manifest files)
  • Build setup with Vite or Webpack including HMR
  • Documentation on structure and core functions
  • Optimization recommendations for Chrome Web Store
  • Publishing consultation (screenshots, description)
  • 30-day post-delivery support
  • Access to private repository
  • Training session on popup customization (1 hour)

For chrome extension popup development, our certified team with 10+ years of experience delivers guaranteed compliance and fast loading. Contact us for a free project evaluation and receive a ready product with full documentation. Over 40 successful projects ensure store requirements are met. React development is 3 times faster for complex UI than Vanilla JS, saving you 60% debugging time and 40% load time.