Urgent.News

What's breaking now, across thousands of outlets.

Tech

The Surprising Complexity of Injecting a UI into Someone Else's Web Page

Originally published at parvejshah.com/blog/building-manifest-v3-ai-chrome-extensions by Parvej Shah . When we started building Leadswave — a LinkedIn brand assistant Chrome extension — the plan seemed straightforward. Detect LinkedIn post elements in the feed, attach a small AI companion button to each one, let users generate engagement responses without leaving the page. A week's work, maybe…

Leadswave, a LinkedIn brand assistant Chrome extension, initially seemed like a simple project to detect LinkedIn post elements in the feed and attach a small AI companion button to each. However, the team soon discovered the complexities involved in injecting the UI into a third-party web page.

When injecting HTML into LinkedIn's document, the content script is working within a page that they don't control, with styles they didn't write and a DOM structure that can change unpredictably. The first version of Leadswave appended a styled div to each post element and mounted a React component inside it. But on the actual LinkedIn feed, Tailwind utility classes either had no effect due to LinkedIn's CSS specificity being higher, or caused unintended effects in LinkedIn's own components as their styles bled into the Leadswave DOM nodes.

To resolve this, the team turned to Shadow DOM, a modern browser feature that allows attaching a shadow root to a host element, creating an isolated DOM subtree with its own style cascade. This way, Leadswave's styles couldn't bleed into LinkedIn's components and vice versa. The mountAssistantWidget function demonstrates how to create a shadow container, attach a shadow root, add styles within the shadow, append a mount point, and finally append both the shadow and mount point to the host element.

Manifest V3 service workers replaced persistent background pages in Manifest V2. Service workers can be terminated by the browser at any time, which can lead to unexpected behavior when developing locally. To avoid relying on module-level variables for persistent state, the team read from storage instead. The extractPostContext function demonstrates how to extract clean context from LinkedIn's DOM by querying specific elements, extracting text nodes, and joining the text together for the AI generation process.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

More from Wednesday 26 August →