When you inject UI onto a page you don't own, there are two real options: iframe or shadow DOM. I picked shadow DOM for rabbitholes, and it came down to one concrete failure mode I kept hitting in the iframe prototype.
Iframes are an isolated browsing context. That isolation is the point, but it cuts both ways: your injected tooltip has no access to the host document's font stack. On a site using a custom web font loaded via @font-face, the iframe renders in whatever the browser's fallback is — usually a system serif — while the surrounding article is in Inter or Georgia or whatever the designer specified. The mismatch is jarring, and fixing it requires reading getComputedStyle from the host and injecting matching declarations into the iframe, which races document load and produces a visible flash before the injection fires.
Shadow DOM doesn't have that problem. It's encapsulated — host-page stylesheet rules don't cascade in, extension styles don't leak out — but font-family and other inherited CSS properties still flow down from the document root. The tooltip renders in the page's own font, no injection, no timing race.
The reset block that makes this work reliably:
:host {
all: initial;
font-family: inherit;
line-height: 1.5;
}
all: initial is the load-bearing line. Without it, high-specificity host rules punch through the shadow boundary on inherited properties and corrupt padding and layout. You reset everything to initial, then explicitly re-inherit only what you want. font-family: inherit is the one you always want.
The secondary win: because shadow DOM mounts in the document tree, getBoundingClientRect on the host selection gives you coordinates you can use directly to position the tooltip. An absolutely-positioned iframe needs manual scroll offset arithmetic on top of that — more surface area for bugs on pages with sticky headers or custom scroll containers.
The extension uses Manifest V3. API key stored in chrome.storage.sync, requests go browser-direct to api.anthropic.com and api.search.brave.com — no server in the middle.
Top comments (0)