DEV Community

J Now
J Now

Posted on

Shadow DOM vs iframe for browser extension tooltips: a build note

I built rabbitholes to keep Wikipedia-style context one highlight away, inline, without opening a new tab. The hard part wasn't the API integration — it was injecting a tooltip into arbitrary host pages without the tooltip looking wrong or breaking the page.

Two options: iframe overlay or shadow DOM.

Iframes are isolated by design, which sounds right, but that isolation cuts both ways. Fonts loaded by the host page aren't available inside an iframe unless you explicitly load them again — and loading them again means a flash of unstyled content while they download. On a long-form article where the reading typeface is part of the experience, the tooltip snapping from system-sans to the correct font mid-render is visually jarring enough that I dropped the approach after one test.

Shadow DOM gives encapsulation without the font problem. The shadow root participates in the browser's font-loading lifecycle alongside the host document, so fonts the page already loaded are available inside the shadow tree immediately. The tooltip renders in the correct typeface on the first paint.

Positioning is also cleaner. The shadow host element lives in the normal DOM, so I can place it with position: absolute using coordinates from Range.getBoundingClientRect() — cursor-relative, no coordinate-space translation required. With an iframe I'd have been fighting two separate viewport frames.

The tradeoff I accepted: shadow DOM isn't true isolation. A host page using all: initial on broad selectors can punch through in some browsers. My mitigation was to explicitly declare every CSS property on the shadow container rather than inheriting any browser defaults — verbose, but reliable across the sites I tested (Wikipedia, Substack, NYT, arXiv).

Everything else in rabbitholes is also built with the minimal-footprint constraint: Manifest V3, no intermediary server, API keys stored in chrome.storage.sync, zero analytics. Requests go browser-direct to api.anthropic.com.

https://github.com/robertnowell/rabbitholes

Top comments (0)