Examples, Code, Pros & Cons
This article covers the most common ways to embed or integrate a third-party UI into your product:
- Iframe embed
- Script tag / JS SDK
- NPM package / component library
- Micro-frontend (MFE) integration
Quick Decision Guide
- Safest, fastest “just embed it” → Iframe
- Quick integration + tight UX (accepts global JS risk) → Script tag / JS SDK
- Best UX + full control + shared design system → NPM package
- Independent deploys + large teams → MFE
1. Iframe Embed
What it is
You render the third-party UI inside an <iframe> pointing to a URL hosted by the vendor (or another internal team).
Basic Example
html
<iframe
src="https://vendor.example.com/widget?tenant=acme"
title="Vendor Widget"
width="100%"
height="700"
style="border:0; border-radius:12px;"
loading="lazy"
/>
Secure Sandbox Example
html
Copy code
<iframe
src="https://vendor.example.com/widget?tenant=acme"
title="Vendor Widget"
width="100%"
height="700"
sandbox="allow-scripts allow-forms allow-popups"
allow="clipboard-read; clipboard-write"
style="border:0;"
/>
Parent ↔ Child Communication (postMessage)
Parent
ts
Copy code
const iframe = document.getElementById("vendor-iframe") as HTMLIFrameElement;
window.addEventListener("message", (event) => {
if (event.origin !== "https://vendor.example.com") return;
if (event.data?.type === "READY") {
iframe.contentWindow?.postMessage(
{ type: "SET_THEME", theme: "dark" },
"https://vendor.example.com"
);
}
});
Child
ts
Copy code
window.parent.postMessage({ type: "READY" }, "https://host.example.com");
Pros
Strong isolation (security, CSS, JS)
Easy rollback
Vendor deploys independently
Cons
Styling consistency is harder
Requires postMessage plumbing
SEO & accessibility limitations
Use When
Vendor is untrusted
You want minimal blast radius
Security matters more than UX polish
2. Script Tag / JS SDK
What it is
A vendor-hosted script injects UI or exposes a global SDK.
HTML Example
html
Copy code
<div id="vendor-root"></div>
<script src="https://cdn.vendor.com/widget/v1/widget.min.js"></script>
<script>
VendorWidget.mount("#vendor-root", {
tenant: "acme",
theme: "light",
});
</script>
React Wrapper Example
tsx
Copy code
import { useEffect, useRef } from "react";
export function VendorWidget({ tenant }: { tenant: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const instance = (window as any).VendorWidget.mount(ref.current, { tenant });
return () => instance?.unmount?.();
}, [tenant]);
return <div ref={ref} />;
}
Pros
Faster than iframe for UX
Easy to integrate
No build-time dependency
Cons (Real Risks)
Executes untrusted JS in your origin
CSS/global JS conflicts
Debugging is painful
Version drift via CDN
Required Safety Measures
Pin versions
Use SRI (integrity)
Lock down CSP
Demand namespaced CSS or Shadow DOM
Use When
Vendor is trusted
Widget is small
You need fast integration
3. NPM Package / Component Library
What it is
You install the vendor UI as a dependency and render components directly.
Install
bash
Copy code
npm install @vendor/ui @vendor/sdk
React Example
tsx
Copy code
import { VendorCheckout } from "@vendor/ui";
export function Checkout() {
return (
<VendorCheckout
customerId="cust_123"
theme="light"
onSuccess={(r) => console.log(r)}
/>
);
}
Pros
Best UX integration
Fully testable
Explicit version control
Styling consistency
Cons
Bundle size impact
Dependency conflicts
Vendor bugs break builds
No isolation
Best Practices
Pin exact versions
Lazy-load heavy UI
Wrap vendor UI with an adapter layer
Use When
UI is core to your product
You control UX and design
You accept ownership of upgrades
4. Micro-Frontend (MFE)
What it is
A separately built and deployed frontend loaded at runtime.
Host Loader Example
ts
Copy code
async function loadRemote(url: string) {
await new Promise<void>((resolve) => {
const s = document.createElement("script");
s.src = url;
s.onload = () => resolve();
document.head.appendChild(s);
});
return (window as any).RemoteApp;
}
const remote = await loadRemote("https://cdn.example.com/remote.js");
const instance = remote.mount(document.getElementById("root"), { tenant: "acme" });
Remote App Contract
ts
Copy code
export function mount(el: Element, opts: { tenant: string }) {
// render app
return { unmount() {} };
}
(window as any).RemoteApp = { mount };
Pros
Independent deploys
Scales across teams
Shared runtimes possible
Cons
High complexity
Version coordination issues
Harder observability
Slower local dev
Use When
Multiple teams
Independent release cycles
Large surface-area UI
Comparison Table
Pattern Isolation UX Complexity Risk
Iframe High Medium Low Low
Script / SDK Low High Low Medium-High
NPM Library Low Very High Medium Medium
MFE Medium High High Medium
Critical Engineering Concerns
Authentication
Avoid long-lived tokens in URLs
Prefer short-lived session tokens
Never expose secrets to iframe URLs
Styling
Use tokens or theme contracts
Avoid global CSS leaks
Prefer Shadow DOM when possible
Performance
Lazy load everything non-critical
Cache remote assets
Watch duplicate bundles (MFE)
Reliability
Loading states
Timeouts
Graceful fallbacks (link-out)
Practical Recommendations
Untrusted vendor → Iframe
Trusted widget → Script SDK (with CSP + SRI)
Core product UI → NPM library
Large org / many teams → MFE (with platform investment)
Alternative Approaches
Web Components
OAuth-style redirect flows
Vendor-hosted portals with callbacks
Bottom line:
Isolation buys safety. Tight integration buys UX. Complexity grows fast.
Choose the least powerful integration that still solves the problem.
Top comments (0)