"Three surfaces, three lifetimes, three information densities. Lesson 3 is the decision matrix — which one earns each ClipDeck feature, and why pushing the wrong feature into the wrong surface is the most common extension UX bug."
The Three Surfaces
- Popup. Tiny, transient. Max ~800×600 pixels, but reasonable size is more like 320×480. Dies on any outside click. Mounted at toolbar-icon click, unmounted the moment focus leaves. Excellent for one-off interactions — settings toggle, quick status, single-button action.
- Side panel. Tall, persistent. Full window height, ~300–400 px wide depending on user preference. Survives clicks on the page; survives tab switches; dies only when the user explicitly closes it. Excellent for ambient context the user references repeatedly.
- Full tab. The biggest. Open with
chrome.tabs.create({ url: 'options.html' })or viachrome_url_overrides. Same context type as a regular web page; can take the whole window. Excellent for dedicated apps, settings pages, onboarding flows, complex multi-step UI.
Lifetime, Compared
| Surface | Open until | Loses focus on | Re-mount cost |
|---|---|---|---|
| Popup | any outside click | everything | load + render every open |
| Side panel | user toggles off | nothing | load on first open, persist after |
| Full tab | user closes tab | nothing | load on first open, persist after |
Popup mounting is cheap but happens often; panel and full-tab mounting is more expensive but happens rarely. This is the main throughput-vs-latency trade.
The ClipDeck Allocation
- Popup — quick actions and stats. "Save current selection" button (which messages the SW to do the actual capture), "Open clip list" button (which opens the side panel), today's count, "Reset counters". Anything that completes in one click and does not need to remain visible.
- Side panel — the clip library. Full list with timestamps, source URLs, search box, filters, inline edit/delete (Track 7). The user keeps it open while reading articles.
- Full tab — reserved for the eventual options page (Track 6 introduces it) and a possible export/import view that needs more room than the side panel offers. ClipDeck v1 ships without a full-tab UI; v2 might.
The decision rule, stated as a question: how long does the user need to see this UI? Seconds → popup. Minutes-to-session → side panel. Long-running task or settings → full tab.
Anti-Patterns
- Cramming a clip library into the popup. Past ten entries the popup feels broken. Symptoms: forced scroll, lost selection on each open, no room for filters. Push to the side panel.
- Putting one-click actions in the side panel. Forces the user to open the panel just to dismiss it. Symptoms: low feature engagement. Push to the popup.
- Building settings inside the popup. Multi-section forms need real estate. Symptoms: tiny inputs, popup auto-close on form interaction. Push to the full tab via
options_page. - Opening a full tab for a quick status check. Disruptive — pulls the user out of the page they were on. Symptoms: user uninstalls. Push to the popup or panel.
Match the surface to the lifetime of the user's intent. Seconds = popup, minutes = panel, sessions = full tab. Wrong surface is the loudest UX bug an extension can ship.
Can the surfaces share code? Yes — popup, side panel, and full-tab pages can all import the same JS modules and share styles. ClipDeck's clip-row renderer can live in a single
clip-row.js imported by panel.js and a future export-page.js. The popup typically has different needs (status-only), but if you find your popup and panel growing parallel render logic, factor it into a shared module rather than duplicating.