DEV Community

Cover image for Common Third-Party GUI Integration Patterns
Samuel Ruiz
Samuel Ruiz

Posted on • Edited on

Common Third-Party GUI Integration Patterns

At some point, almost every product needs to embed or integrate a third-party UI: payments, analytics, scheduling, support widgets, internal tools, or partner features.

There are four common patterns, each with very different tradeoffs around security, UX, ownership, and complexity:

  1. 🧱 Iframe embed
  2. 📜 Script tag / JavaScript SDK
  3. 📦 NPM package / component library
  4. 🧬 Micro-frontend (MFE)

Choosing the wrong one early can lock you into painful rewrites later.


⚡ 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 systemNPM package
  • 🏗️ Independent deploys + large teamsMicro-frontend (MFE)

If you’re unsure, start with iframe. You can always move down the list—but moving up is expensive.


🧱 1. Iframe Embed

🔍 What it is

You render third-party UI inside an <iframe> pointing to a URL hosted by the vendor (or another internal team).

The iframe runs in a separate browsing context, isolated from your app’s JS and CSS.


💻 Basic Example

<iframe
  src="https://vendor.example.com/widget?tenant=acme"
  title="Vendor Widget"
  width="100%"
  height="700"
  loading="lazy"
  style="border:0; border-radius:12px;"
></iframe>
Enter fullscreen mode Exit fullscreen mode

🔐 Secure Sandbox Example

<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;"
></iframe>
Enter fullscreen mode Exit fullscreen mode

🔁 Parent ↔ Child Communication (postMessage)

Parent

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"
    );
  }
});
Enter fullscreen mode Exit fullscreen mode

Child

window.parent.postMessage(
  { type: "READY" },
  "https://host.example.com"
);
Enter fullscreen mode Exit fullscreen mode

✅ 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
  • Security > UX polish
  • You want minimal blast radius

📜 2. Script Tag / JavaScript SDK

🔍 What it is

A vendor-hosted script injects UI or exposes a global SDK that runs inside your app’s origin.


💻 HTML Example

<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>
Enter fullscreen mode Exit fullscreen mode

⚛️ React Wrapper Example

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} />;
}
Enter fullscreen mode Exit fullscreen mode

✅ Pros

  • 🎯 Better UX than iframe
  • ⚡ Fast integration
  • 🧩 No build-time dependency

❌ Cons (Real Risks)

  • ☠️ Executes untrusted JS in your origin
  • 🎨 CSS / global JS conflicts
  • 🐞 Painful debugging
  • 📦 CDN version drift

🛡️ Required Safety Measures

  • 🔒 Pin exact versions
  • 🧾 Use SRI
  • 🚧 Lock down CSP
  • 🧩 Demand namespaced CSS or Shadow DOM

🎯 Use when

  • Vendor is trusted
  • Widget is small
  • Speed matters more than isolation

📦 3. NPM Package / Component Library

🔍 What it is

You install the vendor UI as a dependency and render it directly.

This gives the best UX—and the most responsibility.


📥 Install

npm install @vendor/ui @vendor/sdk
Enter fullscreen mode Exit fullscreen mode

⚛️ React Example

import { VendorCheckout } from "@vendor/ui";

export function Checkout() {
  return (
    <VendorCheckout
      customerId="cust_123"
      theme="light"
      onSuccess={(result) => console.log(result)}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

✅ Pros

  • 🏆 Best UX
  • 🧪 Fully testable
  • 🔢 Explicit version control
  • 🎨 Design system alignment

❌ Cons

  • 📦 Bundle size impact
  • 🔗 Dependency conflicts
  • 💥 Vendor bugs can break builds
  • 🚫 No isolation

🧠 Best Practices

  • 🔒 Pin versions
  • ⏳ Lazy-load heavy UI
  • 🧱 Wrap with adapter components

🎯 Use when

  • UI is core to your product
  • You own UX decisions
  • You accept upgrade ownership

🧬 4. Micro-Frontend (MFE)

🔍 What it is

A separately built and deployed frontend loaded at runtime.


🏗️ Host Loader Example

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;
}
Enter fullscreen mode Exit fullscreen mode

🔌 Remote App Contract

export function mount(el: Element, opts: { tenant: string }) {
  return { unmount() {} };
}

(window as any).RemoteApp = { mount };
Enter fullscreen mode Exit fullscreen mode

✅ Pros

  • 🚀 Independent deploys
  • 🧑‍🤝‍🧑 Team scalability
  • 🔄 Shared runtimes

❌ Cons

  • 🧠 High complexity
  • 🔗 Version coordination pain
  • 🐢 Slower local dev

🎯 Use when

  • Multiple teams
  • Independent release cycles
  • Large UI surface area

📊 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 sessions
  • Never expose secrets to iframes

🎨 Styling

  • Use theme contracts
  • Avoid global CSS
  • Prefer Shadow DOM when possible

⚡ Performance

  • Lazy-load non-critical UI
  • Cache remote assets
  • Watch for duplicate bundles

🛟 Reliability

  • Loading states
  • Timeouts
  • Graceful fallbacks

🧭 Practical Recommendations

  • 🛡️ Untrusted vendor → Iframe
  • ⚠️ Trusted widget → Script SDK
  • 🎯 Core UI → NPM library
  • 🏗️ Large org → MFE

Top comments (0)