Using WordPress? Every integration here is also available as a plugin. Browse the plugin store →

Articles Embedding

Iframe or custom element: how a third-party widget should arrive on your page

Should an embedded third-party widget be an iframe, or a script that defines a custom element?

Choose an iframe when isolation matters more than integration — untrusted content, a separate origin, a hard security boundary. Choose a custom element when the widget has to behave like part of the page: inherit the layout, size to its content, participate in one focus order, and be readable by a screen reader as a single document.

What does an iframe actually give you?

A separate document with a separate origin, which is the strongest isolation the web platform offers. The host page's CSS cannot reach in, the widget's CSS cannot reach out, the JavaScript realms are distinct, and same-origin policy stops the frame reading the host's DOM or cookies. If the embedded content is untrusted, this is not a preference — it is the correct answer.

  • Style isolation, absolutely. No selector on either side can affect the other. Nothing else on the platform is this complete.
  • A security boundary. With sandbox and a permissions policy the host constrains what the frame may do, and the frame cannot escalate.
  • Version independence. The vendor can rewrite everything inside the frame without touching the host page's markup.

What does an iframe cost?

Everything that depends on the widget being part of the page — which, for an interactive widget, is more than people expect. The costs are individually small and collectively decisive.

  • Height. A frame does not size to its content. Either you fix a height and live with the scrollbar, or you build a postMessage resize channel and maintain it — and it will still be wrong for one frame after every content change.
  • Anything that must escape the box. A dropdown, a date picker, a lightbox or a modal cannot render outside the frame's rectangle. Inside a short frame, a calendar popover is clipped by its own container.
  • Focus and scrolling. The frame is one tab stop from the outside and its own document within. Scroll anchoring, scroll-margin for a sticky header, and "scroll the page to this error" all stop working the way they do elsewhere.
  • Typography and theme. Nothing inherits. Font family, type scale and the host's dark mode all have to be re-sent into the frame and re-applied, and any mismatch reads as a foreign object dropped on the page.
  • Assistive technology. A frame is announced as a separate document. The heading structure inside it does not join the page's outline, which weakens exactly the linear reading that a screen-reader user relies on.
  • Crawlers and links. Content in a frame is a different URL. Whether and how it is associated with the host page is not something you control, and a link to a specific state inside the frame is not a link the host page can produce.

What does a custom element give you instead?

A real node in the page's own document. It takes part in normal layout, so it sizes to its content and reflows with the column it sits in. It shares one focus order with the rest of the page. Its headings join the page outline. A modal it opens can cover the viewport, because there is no rectangle to escape.

<script src="https://cdn.wpistatic.com/platform.js" async></script>
<wpi-bookings embed-key="YOUR_EMBED_KEY"></wpi-bookings>
Illustrative markup. Two lines, no build step — a custom element is valid HTML in any framework or in a hand-edited file.

It also degrades in a more useful way. An element the browser does not recognise is an unknown element, not an error: it renders as an empty inline box until the script defines it, at which point it upgrades in place. There is no framework requirement on the host, and nothing to reconcile with the host's build tooling.

Does a custom element need shadow DOM?

It does not, and the decision is a genuine trade rather than a formality. A shadow root gives style encapsulation that is nearly as strong as an iframe's while keeping the element in the page's layout and focus order. That is the textbook answer, and for most widgets it is the right one.

It stops being the right one when the widget's own UI library injects its styles into document.head. A CSS-in-JS engine that appends a <style> element to the head is emitting styles that do not cross a shadow boundary in either direction — so a component mounted in a shadow root renders unstyled. The WPIntegrate components hit exactly this: they are built on Fluent UI, whose Griffel engine inserts into document.head, so they render in the page's own DOM rather than in a shadow root.

The cost of that choice has to be stated rather than hidden: host-page CSS can reach the widget. What contains it is the library's own resets and generated class names, plus per-instance styling controls that let the widget be matched to the host deliberately instead of accidentally. If you are choosing a widget, this is a fair thing to ask a vendor — and a vendor who cannot tell you which one they use has not thought about your page.

How do you decide which one you want?

IframeCustom element
Style isolationCompleteShadow root, or the library's own resets
Security boundarySeparate origin, sandboxableShares the page's origin and JS realm
Sizes to its contentNo — fixed or postMessageYes, like any element
Popovers and modalsClipped to the frameFree of the page
Focus orderA separate documentOne order with the page
Screen-reader outlineAnnounced separatelyPart of the page outline
Inherits host themeNo, must be re-sentYes, and can be overridden
  • Take the iframe for content you do not control or do not trust, for anything handling payment details, and where a hard security boundary is the requirement rather than a nice-to-have.
  • Take the custom element for a widget that is meant to read as part of the page — a booking flow, a document browser, a team directory, a form — and where clipped popovers and a fixed height would be visible defects.

One test cuts through most of the argument: would a reader be surprised to learn this section of the page came from somewhere else? If the honest answer is yes, it should not be an iframe.

Questions people ask about this

Is an iframe more secure than a custom element?

Yes, for the host page — a frame is a separate origin, can be sandboxed, and cannot read the host's DOM or cookies. A custom element shares the page's origin and JavaScript realm, so embedding one is a statement of trust in the vendor, which is why the code should come from a host you have reason to trust.

Why do iframes need a postMessage resize script?

Because an iframe does not size to its content — the parent sets its height, and the parent cannot see inside it. The frame has to measure itself and message the height out, which is a channel someone has to write, load and maintain on both sides.

Do custom elements work outside React or Vue?

Yes. A custom element is part of the HTML platform, so it works in plain HTML with no build step and inside every mainstream framework. That is the practical reason to prefer one for a widget distributed to sites you do not control.

Do WPIntegrate components use shadow DOM?

No, and deliberately. They are built on Fluent UI, whose Griffel styling engine inserts its styles into document.head, and those styles do not cross a shadow boundary — so a shadow-mounted component would render unstyled. They render in the page's DOM instead, with Fluent's own resets and generated class names limiting what host CSS can disturb.

Still the wrong answer for your case? Then the case is worth hearing.

These articles describe the general shape. Tenants differ, policies differ, and the interesting questions are the ones where the general shape does not fit.