Choosing Between Popup, Side Panel and Tab
Pick the right MV3 surface for each feature: toolbar popup, side panel, extension tab, popup window or injected UI, judged by persistence, size, page context, cross-browser support and how users reach it.
Table of Contents
Every extension feature needs somewhere to live, and the choice shapes everything after it. Put a note-taking editor in the popup and users lose their text every time they click the page. Put a one-click “save” button in a side panel and users must open a panel to press a button. Put a dashboard in a tab and nobody finds it. MV3 offers five surfaces — the toolbar popup, the side panel, a full extension page in a tab, a standalone popup window, and UI injected into the page — and each fits a different kind of interaction. This guide compares them on the properties that decide the fit. It belongs to extension popup architecture.
The properties that decide the surface
Five properties separate the surfaces. Persistence: does it stay open while the user interacts with the page? The popup does not; the side panel, tab, window and injected UI do. Size: the popup is capped around 800×600 pixels; the side panel is a user-resizable column; tabs and windows can be any size. Page context: can the user see the page at the same time? Side panels and injected UI sit beside or on the page; a tab replaces it. Reachability: how does the user get there? Toolbar click, keyboard shortcut, context menu, or a link from elsewhere. Portability: the side panel is Chrome-specific (Firefox has a sidebar with a different API; Safari has neither), while popups, tabs and injected UI work everywhere.
Step-by-step: choose per feature
1. Classify the interaction
1features.md
2Save article one click, then done → popup or action click
3Quick settings a few toggles → popup
4Reading notes write while reading, minutes → side panel
5Search saved items type, browse results, open one → popup (search) / tab (browse all)
6Full library sort, filter, bulk edit → tab
7Timer / chat visible across tabs and windows → popup window
8Highlight on page tied to page content → injected UI
Execution context: a planning document. Two questions do most of the work: how long does the interaction last, and does the user need to see the page while doing it? Seconds and no → popup. Minutes and yes → side panel or injected UI. Minutes and no → tab.
2. Use the popup for quick, self-contained actions
1{ "action": { "default_popup": "popup.html", "default_title": "Readable" } }
Execution context: the manifest. The popup suits actions that finish in seconds: a toggle, a save, a glance at status. It gets the active tab via activeTab the moment it opens. Design every popup interaction so that closing the popup at any moment loses nothing — persist as the user types, and hand longer work to the worker, as in running work that outlives the popup.
3. Use the side panel for work alongside the page
1{ "permissions": ["sidePanel"], "side_panel": { "default_path": "sidepanel.html" } }
1// sw.js — open the panel from the toolbar instead of a popup
2chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
Execution context: the manifest and service worker. The side panel stays open while the user reads, scrolls and switches tabs, which is what note-taking, research, AI assistants and reference tools need. Setting openPanelOnActionClick makes the toolbar button open the panel — but then you lose the popup for that button, so decide which is the primary surface. See building a side panel UI in MV3.
4. Use a tab for full-page tools
1// popup.js — a link from the quick surface to the full one
2document.querySelector("#open-library").addEventListener("click", async () => {
3 await chrome.tabs.create({ url: chrome.runtime.getURL("library.html") });
4 window.close();
5});
Execution context: the popup. A library, dashboard or settings area with tables and bulk actions needs room. Opening it in a tab gives full width, history, bookmarks and the ability to keep it open. Reuse an existing tab rather than opening duplicates, as described in opening and tracking extension pages in tabs. Closing the popup after opening the tab avoids it lingering over the new page.
5. Use injected UI when the feature is about the page
Highlights, inline annotations, a translation tooltip next to selected text, a “save” button on images — these belong on the page itself, where the user’s attention already is. Injected UI has the most moving parts (style isolation, cleanup, frameworks on the page), so reserve it for features that truly need page context; see in-page overlays and injected UI.
6. Plan fallbacks for missing surfaces
1export async function openReadingPanel(windowId) {
2 if (chrome.sidePanel?.open) return chrome.sidePanel.open({ windowId });
3 if (globalThis.browser?.sidebarAction?.open) return browser.sidebarAction.open();
4 return chrome.tabs.create({ url: chrome.runtime.getURL("sidepanel.html") });
5}
Execution context: the service worker or popup, from a user gesture. Building every panel as an ordinary extension page means it can be shown as a Chrome side panel, a Firefox sidebar, or a tab in Safari. Design its layout to work in a narrow column and a full tab.
7. Share state, not instances
Whatever combination you choose, each surface is a separate document. Keep state in chrome.storage and let each surface render from it and listen for changes, so a note typed in the side panel appears in the library tab without any direct communication between them.
Common mistakes
- Long-form input in the popup. It closes on the first click outside.
- Side panel for one-click actions. An extra step for no benefit.
- A hidden full-page tool. Link to it from the popup and options.
- Chrome-only surfaces without fallbacks. Safari users get nothing.
- Surfaces talking to each other directly. Share storage instead.
Cross-browser variation
- Chrome / Edge: all five surfaces;
sidePanelwith per-tab paths andopenPanelOnActionClick. - Firefox: popup, tab, window and injected UI as in Chrome; the sidebar uses
sidebar_actionand is shared across tabs in a window. - Safari: popup, tab and injected UI; no side panel; popup windows behave more like normal windows.
Verification
- For each feature, perform the core task and click the page mid-task; confirm nothing is lost.
- Confirm every surface is reachable within two actions from the toolbar.
- Load the extension in Firefox and Safari and confirm each feature has a working surface.
- Change state in one surface and confirm the others reflect it.
FAQ
Can I have both a popup and a side panel on the toolbar button?
Not at the same time. Choose one as the click behaviour, and open the other from a button, context menu or keyboard shortcut.
Is the options page a surface?
Yes — a tab-like page for configuration, opened from the extensions menu or with runtime.openOptionsPage(). Keep it for settings, not daily use.
Do surfaces affect permissions?
sidePanel needs its permission; the others need none beyond what their features use.
Related
- Why the popup closes and how to work with it — the popup’s constraints.
- Side panel support across browsers — the panel’s portability.
- Creating popup windows with chrome.windows — the floating option.
- Extension popup architecture — the parent topic.