← All posts

Why our widget lives inside a Shadow DOM

Embedding third-party UI on someone else's page is a CSS minefield. Shadow DOM is the only sane defuser.

If you have ever shipped an embeddable widget, you know the moment: the support engineer pings you with a screenshot of your perfectly designed chat bubble, now squashed, recolored, and missing its border because the host site set * { box-sizing: content-box } and button { font-size: 22px !important } thirteen years ago.

You cannot win a CSS war on someone else’s repo. You can only secede.

What Shadow DOM gives you

A Shadow root is a parallel DOM tree that the host’s stylesheets cannot reach. From the host’s perspective the widget is a single opaque element. From inside the widget, host CSS does not exist.

That isolation buys three things:

  • Predictable rendering across every CMS, marketing template, and Wordpress theme on earth.
  • No font-size cascades — your 12px stays 12px.
  • No specificity arms races — you do not need .fb-button.fb-button--primary { font: 14px/1.4 system-ui !important } written six layers deep.

What it costs

  • Slot composition is awkward. Passing styled children in is harder than a normal portal.
  • Devtools are clunkier. Inspecting a shadow tree is a couple extra clicks.
  • Some libraries assume document scope. Tooltip libraries that append to document.body need to be told otherwise.

We decided the tradeoffs were obvious. The widget should look the same on a Webflow landing page and a hand-rolled Rails app. Shadow DOM is the only mechanism that delivers that without asking customers to “please remove this rule from your global stylesheet.”

A small lesson about themes

Theme tokens still flow in via CSS custom properties — those do pierce the shadow boundary. So the visitor’s host page can override --fb-primary-color and the widget reskins instantly. Boundary, but with a controlled door.

More from the blog

All posts →
Maya Reyes ·

Citations vs hallucinations: why grounding matters

An unsourced answer is a guess wearing a tie. Here's how grounding closes the gap between confidence and correctness.

The FluentBot team ·

Why we built FluentBot

Most chatbots hallucinate because they were never trained on your content. We took a different path.

Priya Anand ·

Treat your content gaps as a roadmap

Every unanswered question is a backlog item your customers wrote for you. Stop ignoring them.