--- title: "Embedded UI Iframe Mode Reference" slug: "embedded-ui-iframe-mode-reference" tags: ["embedded-ui", "reference-guides"] status: "update" updated: 2026-10-13T18:18:59Z published: 2026-10-13T18:18:59Z canonical: "docs.unqork.io/embedded-ui-iframe-mode-reference" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.unqork.io/llms.txt > Use this file to discover all available pages before exploring further. # Embedded UI Iframe Mode Reference Embedded UI offers two ways to embed Unqork modules into an external web page. The default approach uses a Web Component with Shadow DOM isolation. The second approach, iframe mode, loads the module inside a native browser iframe, which provides complete separation of CSS, JavaScript, and DOM between the host page and the module. This stronger isolation comes with tradeoffs: the host page and module communicate through a messaging system instead of direct page access. Activate iframe mode by passing `iframe: true` to `mountModule()`. > [!NOTE] > Iframe mode is currently Centauri only. Attempting to mount a Vega (v2.x) module in iframe mode throws an error. Workflow mounting (`mountWorkflow()`) always uses the web component . ## When to Use Iframe vs. Web Component Use the following table to choose the right embedding approach. Most integrations should begin with the Web Component approach and switch to iframe mode only when complete CSS, JavaScript, or DOM isolation is required. | Criterion | Web Component (default) | Iframe | | --- | --- | --- | | CSS isolation | Shadow DOM | Browser-level | | JS isolation | Shared `window` | Separate browsing context | | Communication | Direct DOM and events | postMessage API | | Authentication | Shared cookies | Shared cookies | | Resize | Automatic (content is in-page) | Auto-resize through postMessage | | Data access | Direct Redux and Angular scope | Request and response protocol | | Performance | Better | Slight overhead | | Multiple modules | Limited | Naturally supports multiple | | Deep linking | Not supported | Not supported | ## Embedded UI Iframe Architecture This diagram displays how the host page and the iframe communicate. Every interaction between them passes through the postMessage API, managed by the files running inside the iframe. ![Diagram](https://cdn.us.document360.io/15548f06-2fba-434c-b0c1-5df88317dbd7/Images/Documentation/api_upload_20261013_181857_537d9c181efe443091bab8ca1724c588.svg?sv=2026-02-06&spr=https&st=2026-11-08T10%3A17%3A55Z&se=2026-11-08T11%3A17%3A55Z&sr=c&sp=r&sig=LG0vm0suWCJOMR1%2BtbSJRUMUafuFp9KOWhQB3CxNuoc%3D) ## Handshake Protocol Before any data exchange, the iframe and host establish a secure channel: ![Diagram](https://cdn.us.document360.io/15548f06-2fba-434c-b0c1-5df88317dbd7/Images/Documentation/api_upload_20261013_181857_38deb28bcf1747259a0c7838e19792ab.svg?sv=2026-02-06&spr=https&st=2026-11-08T10%3A17%3A55Z&se=2026-11-08T11%3A17%3A55Z&sr=c&sp=r&sig=LG0vm0suWCJOMR1%2BtbSJRUMUafuFp9KOWhQB3CxNuoc%3D) ## Security Model The iframe embed uses five security layers. Each layer blocks a different type of attack, so the channel stays secure even if one layer fails. | Layer | Module | Purpose | | --- | --- | --- | | Origin validation | `embed-security.js` | Checks `event.origin` against an allowlist of trusted origins before processing any message. | | Rate limiting | `embed-security.js` | Allows a maximum of 100 messages per second (configurable). Messages above the limit are dropped. | | HMAC signing | `embed-security.js` | Uses SHA-256 (Hash-based Message Authentication Code) to verify message integrity through a shared secret established during the handshake. | | sanitization | `embed-security.js` | Enforces string length limits, strips script tags, and applies object depth limits on all incoming data. | | Sandbox attribute | Browser | The iframe is created with `allow-scripts allow-same-origin allow-forms` (configurable). This restricts what the iframe content can do in the browser. | ## Auto-Resize The iframe automatically resizes to fit its content. Four mechanisms work together to detect size changes: - **ResizeObserver**: Watches the document body for element size changes. - **MutationObserver**: Detects DOM changes, like new components rendering. - **Window resize listener**: Handles viewport size changes. - **Polling fallback**: Runs every 500 ms in older browsers that don't support ResizeObserver. Height changes are debounced by 50 ms and sent to the host through postMessage. CSS overrides injected inside the iframe prevent `position: fixed` elements from causing resize feedback loops. ## EmbedDisplayController: Inside the Iframe The `EmbedDisplayController.js` controller runs inside the iframe and manages all communication between the iframe and the host page: - Detecting the iframe context through the `iframeId` query param. - Injecting embed CSS overrides. - Initializing SecurityManager, MessagingManager, APIHandlers, ResizeManager, and EventManager. - Listening for incoming API requests. - Cleaning up on `$scope.$destroy`. ## Embedded UI Iframe Limitations Be aware of the following constraints before building an iframe-mode integration. Some are fundamental browser limitations; others are specific to how iframe mode works. | Limitation | Description | | --- | --- | | Centauri only | Vega modules cannot be iframe-embedded. Attempting to do so throws an error. | | No workflow support | `mountWorkflow()` always uses the web component path. Passing `iframe: true` has no effect on workflows. | | Cross-origin cookies | The `allow-same-origin` sandbox attribute is required for session cookies to work. Removing it breaks authentication. | | No direct DOM access | The host page cannot query elements inside the iframe. All interaction must go through the IframeAPI. | | Timeout risk | API calls default to a 20-second timeout. Large or complex forms may need a longer timeout set explicitly. | ## Detailed Feature Comparison: What Does Not Work in Iframe Mode The tables below list features and behaviors that are unavailable or work differently in iframe mode compared to the default web component mode. ### Unsupported Features The following features are fully supported in Web Component mode but are not available when using iframe mode. | Feature | Web Component | Iframe | Detail | | --- | --- | --- | --- | | Workflow mounting | ✓ | ✗ | `mountWorkflow()` always renders through the web component path. Passing `iframe: true` has no effect on workflows. | | Vega (v2.x) modules | ✓ | ✗ | Iframe mode only supports Centauri (v1.x). Attempting to mount a Vega module with `iframe: true` throws an error. | | `onRuntimeError` callback | ✓ | ✗ | The global `runtime.onRuntimeError(callback)` handler receives errors surfaced from `embed-utils.surfaceEmbedError()`. These `CustomEvent` dispatches happen on the iframe's own `window`, not the host `window`, so the host callback never fires. | | `unqork-embed-error` DOM event | ✓ | ✗ | The event is dispatched on the iframe's own `window`, not the host `window`, so it does not reach the host page. Use `IframeAPI.on('error', callback)` to handle errors in iframe mode. | | Direct submission data access | ✓ (through Redux/Angular scope) | ✗ (async only) | In web component mode, the Angular scope and Redux store live on the host `window`, so data is accessible. In iframe mode, all data access passes through the async `IframeAPI.getSubmissionData()` or `getComponentValue()` calls over postMessage. | | `recover()` method | ✓ | ✗ | The runtime `recover()` method reloads the module inside the current Shadow DOM. There is no equivalent postMessage action defined for iframe mode. | | `persistWorkflowState` option | ✓ | ✗ | Only applies to `mountWorkflow()`, which is web-component-only. | | `moduleData` pre-fetch pass-through | ✓ | ✗ | In web component mode, pre-fetched module JSON can be passed as `moduleData` to avoid a double fetch. The iframe loads through a URL (`#/embed/display/{moduleId}`), so the module is always fetched inside the iframe. | ### Behavioral Differences The following features work in both modes but behave differently. Review the behavioral differences below to avoid unexpected behavior in your integration. | Feature | Web Component Behavior | Iframe Behavior | Impact | | --- | --- | --- | --- | | CSS isolation | Shadow DOM (good, not perfect): inherited properties like `font`, `color`, and `cursor` can leak in from the host page. | Browser-level: complete isolation; no style leakage in either direction. | Iframe is stronger; web component may need `:host` overrides for inherited styles. | | JS global isolation | Shared `window`: Angular, jQuery, and Redux all live on the host `window`, creating potential namespace collisions. | Separate browsing context with complete JavaScript isolation. | Iframe eliminates global pollution but prevents direct programmatic access. | | Authentication | Shared cookies; `isAuthenticated()`, `authenticateAnonymous()`, `authenticateReferString()`, and login pop-up all work directly. | Shared cookies through the `allow-same-origin` sandbox flag; auth methods work but the login pop-up opens from the host origin. | Removing `allow-same-origin` from sandbox breaks authentication entirely. | | Error surfacing | Errors dispatched as `CustomEvent('unqork-embed-error')` on host `window`; caught by `onRuntimeError` callback. | Errors stay inside the iframe `window`; host must use `IframeAPI.on('error', callback)` if the iframe-side code emits them. | Host error handling requires different wiring. Currently, iframe-side error events are not forwarded to the host. | | Auto-resize | Automatic: content is in the host DOM, so the container grows naturally. | postMessage-based: `embed-resize.js` uses `ResizeObserver`, `MutationObserver`, and polling inside the iframe, then sends height through postMessage. | Slight latency (debounced 50 ms). CSS `position: fixed` elements inside the iframe can cause sizing loops; the resize manager injects overrides to prevent sizing loops. | | Component value mutation | Direct through Angular scope or Redux dispatch. | Async through `IframeAPI.setComponentValue(componentId, value)` with a postMessage round-trip. | Subject to 20-second default timeout; large data inputs are sanitized (string max 10,000 chars, array max 1,000 items, object max 100 keys, max depth 5). | | Form submission trigger | Direct through Angular `$scope.$emit('buttonClick', ...)` or Redux action. | Async through `IframeAPI.triggerSubmit()`. | Returns a promise; timeout applies. | | Custom events from module | `unqork-embed-module-mounted`, `unqork-embed-workflow-navigate`, and so on dispatched on host `window`. | Module events fire inside the iframe `window`; only events explicitly forwarded by `embed-events.js` are available through `IframeAPI.on(eventName, callback)`. | Not all web-component-mode events have iframe equivalents. | | `destroy()` behavior | Replaces the custom element with a fresh empty instance of the same tag, clearing the Shadow DOM. | Removes the iframe element from the DOM and cleans up postMessage listeners and pending requests. | Both allow re-mounting after destroy. | | Multiple modules on one page | Limited: only one Angular bootstrap per page. | Naturally supported: each iframe is an independent Angular instance. | Iframe is the recommended path when multiple modules are needed on a single page. | | Navigation guard scope | `document`-level click listener blocks `<a>` navigations inside the Shadow DOM. | Browser sandbox handles navigation; `allow-top-navigation` is intentionally omitted from the default sandbox string. | If `allow-top-navigation` is added to the sandbox, the iframe can navigate the host page. Avoid adding the `allow-top-navigation` flag. | ### Iframe Data Sanitization Limits All data flowing through the postMessage API is sanitized by `embed-security.js`. These limits do not apply to web component mode. | Constraint | Limit | | --- | --- | | String length | 10,000 characters (truncated) | | Array length | 1,000 items (truncated) | | Object key count | 100 keys per object | | Nesting depth | 5 levels | | Script tags | Stripped from all strings | | Functions and symbols | Removed (replaced with `null`) | | Message rate | 100 messages per second (configurable) | ## Centauri Component Compatibility: Iframe vs. Web Component The following sections document specific Centauri components that have limited or broken functionality in Web Component (Shadow DOM) mode but work correctly in iframe mode. These limitations stem from third-party libraries that assume they operate in a standard `document` context, which holds true in an iframe but breaks inside a Shadow DOM. ### Components with Known Limitations in Web Component Mode | Component | Library | Limitation in Web Component (Shadow DOM) | Root Cause | | --- | --- | --- | --- | | **RichTextEditor** | CKEditor 5 (`@unqork/ckeditor5-build`) | Toolbar drop-downs, dialogs, and balloon panels render outside the Shadow DOM. CKEditor's internal DOM queries target `document.body` for overlay positioning. Comments and track-changes sidebars may fail to attach. | CKEditor appends UI layers to `document.body`. Inside Shadow DOM, the appended UI layers appear outside the shadow tree, losing CSS isolation and event context. | | **DynamicGrid** (AG Grid) | `@ag-grid-community/react`, `@ag-grid-enterprise/*` | Pop-up editors, filter panels, column menus, and context menus render at `document.body` through `popupParent: document.querySelector('body')`. Drop-down cell editors (react-select) explicitly portal to `document.body`. These pop-ups display outside the Shadow DOM, unstyled and potentially clipped. | AG Grid's `popupParent` defaults to `document.body`. The cell editors (`singleSelectEditor.js`, `multiSelectEditor.js`) set `menuPortalTarget = document.body`. | | **Chart** | Highcharts + Handsontable | Highcharts' exporting module creates a hidden iframe and form on `document.body` for PNG, SVG, and CSV download. Tooltip elements may be appended outside the component container. Handsontable data table injects drop-down editors to `document.body`. | Highcharts exporting appends to `document.body`. Handsontable cell editors and autocomplete drop-downs escape the Shadow DOM boundary. | | **Sheet** (Spreadsheet) | Handsontable Pro (`handsontable-pro`) | Autocomplete and drop-down cell editors, context menus, and comment overlays are appended to `document.body`. These elements are invisible (lack styles) or positioned incorrectly in Shadow DOM. | Handsontable internally uses `document.body.appendChild()` for overlays and floating editors. | | **DateInput** (legacy `datetime`) | Flatpickr | Calendar drop-down is appended to `document.body` by default. Flatpickr queries `document` for positioning and uses `document.addEventListener` for outside-click detection that doesn't account for Shadow DOM event retargeting. | Flatpickr's `appendTo` defaults to `document.body`; its outside-click handler uses `document.addEventListener('click')` which receives retargeted events in Shadow DOM. | | **DateInput** (v2) | Pikaday + Cleave.js | ⚠ Partially mitigated: the codebase includes Shadow DOM workarounds (detecting `ShadowRoot`, setting `container` to shadow root, using `composedPath()` for click detection). However, keyboard navigation, scroll-aware repositioning, and some edge-case outside-click scenarios remain fragile. | Pikaday's `_onClick` handler relies on `event.target` which is retargeted in Shadow DOM. The workaround addresses outside-click detection but may not cover all interaction paths. | | **Select** (v1, ui-select) | Angular `ui-select` | ⚠ Partially mitigated: `spa-embed.js` patches `uiSelectDirective` with a Shadow DOM workaround for outside-click detection. However, the drop-down options list positioning still depends on `document.body` and may overflow or clip incorrectly. Multi-select tags input may lose keyboard focus handling. | `ui-select`'s `onDocumentClick` uses `element.contains(event.target)`, which fails in Shadow DOM due to event retargeting. The existing patch handles close-on-click but not positioning. | | **Map V2** | Google Maps JavaScript API (`window.google.maps`) | Google Maps loads scripts globally through `<script>` tags appended to `document.head`, and queries `document` for its container element. The map renders inside the shadow tree (the div is local), but autocomplete widgets (`google.maps.places.Autocomplete`) append suggestion drop-downs to `document.body`. Info windows and controls may have z-index issues. | Google Maps API inserts auxiliary DOM (pac-container for autocomplete, info windows) at `document.body`. These are unstyled and positioned incorrectly relative to the shadow-contained map. | | **Address Dropdown** | Google Places (through Map service) + `react-select/async` | The Google Places autocomplete suggestions drop-down (`.pac-container`) is appended to `document.body`, rendering outside the Shadow DOM. Users see suggestions appear behind or displaced from the input field. | Google's `pac-container` div is injected into `document.body` and cannot target a Shadow DOM container. | | **Recaptcha** | `react-google-recaptcha` / Google reCAPTCHA API | reCAPTCHA widget injects its iframe and badge into `document.body`. The invisible badge (`data-badge`) renders outside the shadow tree. Challenge pop-ups may fail to anchor correctly to the component. | Google reCAPTCHA inserts challenge iframes and badges at `document.body`. Script loading also targets `document.head`. | | **Plaid** (Plaid Link) | Plaid Link SDK (external script) | Plaid Link opens a modal overlay attached to `document.body`. In Shadow DOM, the overlay renders outside the embed container, lacks styling context, and may have z-index conflicts with the host page. | `Plaid.create()` appends its modal iframe overlay to `document.body`. | | **Dataworkflow** (Data Mapper v1) | GoJS (`window.go`) | GoJS appends measurement elements to `document.body` (measuring text widths, canvas sizing). Tooltips use `go.HTMLInfo` which creates DOM elements at document level. Inspector panel (`datainspector.js`) uses `document.getElementById` for its container. | GoJS library code (`go.js` line 14070+) directly calls `window.document.body.appendChild()`. The inspector uses `document.getElementById(divid)` which doesn't find elements inside Shadow DOM. | | **Plugin** (Integrator) | Internal (XHR + DOM spinner) | Adds/removes CSS classes on `document.body` (`integrator-wait`) to show/hide a global spinner overlay. Inside Shadow DOM, the `integrator-wait` class is applied to the host page `<body>`, not the embedded container. The spinner overlays the entire host page, not just the embedded module. | Direct `document.body.classList.add/remove('integrator-wait')`. | | **SweetAlert2 Modals** | SweetAlert2 (`swal2`) | Used across various components for confirmation dialogs. SweetAlert2 creates modal overlays at `document.body`. The embed-loader injects swal2 CSS into `document.head` as a workaround, but the modal still renders outside the shadow root, breaking visual containment and focus trapping. | SweetAlert2 appends its overlay container to `document.body`. CSS is injected to document head, but DOM remains external to shadow tree. | ### Components That Work Correctly in Both Modes The following components work correctly in both embedding modes and do not require special handling or workarounds. | Component | Notes | | --- | --- | | **Textfield**, **Textarea**, **Number**, **Email**, **Password**, **PhoneNumber** | Standard input elements; no external DOM manipulation. | | **Button**, **Hidden**, **Calculator**, **Transformer** | Logic-only or simple DOM; no portaling. | | **Checkbox**, **Checkboxes**, **Radio** | Native form controls; work in any container. | | **FileInput** | Uses `react-dropzone` which operates on its container element. No global DOM access. | | **Signature** | Uses `signature_pad` on a `<canvas>` element in the component tree. No external DOM access. | | **Markdown** | Uses `marked` for parsing; renders sanitized HTML inline. No external DOM. | | **Image**, **Typography**, **HTMLElement** | Static rendering; no third-party DOM manipulation. | | **Progress**, **Timer** | Visual-only components using local state. | ## Iframe-Only Capabilities The following tables document features, behaviors, and guarantees that are exclusively available or only work correctly in iframe mode. ### Features Available Only in Iframe Mode These features are exclusively available in iframe mode. They are not available in Web Component mode. | Feature | Status in Iframe | Why Web Component Cannot Provide This | | --- | --- | --- | | **Multiple modules on one page** | ✓ Natively supported | Web component is limited to a single Angular bootstrap per page. Mounting a second module in web component mode produces undefined behavior. Each iframe is an independent Angular instance. | | **Complete JavaScript isolation** | ✓ Separate browsing context | Web component shares the host `window`. Angular, jQuery, and Redux globals leak onto the host page, risking namespace collisions with host-page frameworks (React, Vue, another Angular instance, and so on). | | **Complete CSS isolation (no inheritance leakage)** | ✓ Browser-level | Shadow DOM blocks direct style selectors but cannot block inherited CSS properties (`font-family`, `color`, `line-height`, `cursor`, and so on). These leak into the web component from the host page. | | **Host page crash protection** | ✓ Contained | An uncaught exception in the module's Angular runtime terminates only the iframe's JavaScript context. In web component mode, uncaught errors propagate on the shared `window` and can crash host-page error boundaries or monitoring tools. | | **IframeAPI programmatic interface** | ✓ Full `IframeAPI` object returned | Web component returns an `HTMLElement`; data access requires direct Angular scope or Redux store inspection on the shared `window`. The `IframeAPI` offers a typed, promise-based contract (`getSubmissionData`, `getComponentValue`, `setComponentValue`, `getComponentDefinition`, `triggerSubmit`). | | **Event subscription through `api.on()`** | ✓ `submit`, `error`, `navigate`, `locationChange` | Web component relies on `CustomEvent` dispatches on the host `window`, which are more fragile and less discoverable. The `IframeAPI.on()` pattern provides explicit subscribe/unsubscribe with payload typing. | | **HMAC-signed message integrity** | ✓ SHA-256 signed postMessage | Not applicable to web component (communication is direct DOM access; no message channel to sign). Iframe mode signs every sensitive message to prevent injection from rogue `postMessage` callers. | | **Input sanitization on data exchange** | ✓ Enforced automatically | Web component provides raw access to Angular scope; no sanitization layer exists. Iframe mode truncates strings (10,000 chars), arrays (1,000 items), limits object keys (100) and depth (5), and strips `<script>` tags. | | **Rate limiting on communication** | ✓ 100 msg/s (configurable) | Not applicable to web component. Iframe mode throttles incoming messages to prevent denial-of-service through postMessage flooding. | | **Configurable sandbox policy** | ✓ Through the `sandbox` option | Web component has no equivalent; the module inherits full host-page privileges. Iframe sandbox allows granular permission control (`allow-scripts`, `allow-same-origin`, `allow-forms`, `allow-popups`). | | **Navigation confinement (no host-page redirect)** | ✓ `allow-top-navigation` intentionally omitted | Web component uses a `document`-level click listener to intercept `<a>` navigations, but the click listener is a best-effort guard; programmatic `window.location` changes in Angular can still escape. The iframe sandbox physically prevents top-frame navigation. | | **Secure handshake before data exchange** | ✓ Three-step handshake protocol | Not applicable to web component. The iframe establishes a verified channel (`ready-for-init` → `init` with secret → `ready`) before any API call is accepted. | | **Per-request timeout control** | ✓ Configurable per API call (default 20 s) | Web component data access is (Angular scope), so there is no timeout concept. Iframe mode lets callers pass a `timeout` parameter to any `IframeAPI` method to control wait duration. | ### Behaviors That Work Correctly Only in Iframe Mode Several behaviors that are unreliable in Web Component mode work correctly in iframe mode due to how browsers handle iframes versus Shadow DOM boundaries. | Behavior | Iframe Correctness | Web Component Issue | | --- | --- | --- | | **Third-party library conflict avoidance** | ✓ Guaranteed | If the host page loads jQuery, Lodash, Moment, or any library that conflicts with the versions bundled in the Unqork SPA, the web component shares the same `window` and version collisions occur silently. The iframe loads its own dependency tree in isolation. | | **Content Security Policy (CSP) separation** | ✓ Independent CSP | The web component inherits the host page's Content Security Policy (CSP). If the host has a restrictive CSP that doesn't allow `unsafe-eval` or inline styles, the Angular module may fail to bootstrap. The iframe loads from the Unqork origin and applies its own CSP headers. | | **Memory leak containment on destroy** | ✓ Full GC on iframe removal | When the iframe is removed from the DOM, the browser garbage-collects the entire browsing context (all Angular scopes, watchers, jQuery caches, template caches). In web component mode, `destroy()` replaces the custom element, but leaked references on the shared `window` (global event listeners, timers, cached `$http` interceptors) may persist. | | **Cookie and storage partitioning** | ✓ Predictable | In web component mode, `localStorage` and `sessionStorage` are shared with the host page; key collisions are possible. The iframe uses the same origin's storage but runs in a separate execution context, preventing accidental key overwrites between host logic and module logic. | | **`window.location` mutation safety** | ✓ Cannot affect host | In web component mode, any code that reads or writes `window.location` (for example, query-param utilities or router guards) operates on the actual host page URL. In iframe mode, `window.location` inside the module is scoped to the iframe's browsing context. | | **Error monitoring isolation** | ✓ Separate `window.onerror` / `unhandledrejection` | Host page error monitoring (Sentry, Datadog, and so on) attaches to `window.onerror`. In web component mode, module errors trigger host monitors, producing noise. In iframe mode, module errors stay inside the iframe's error handlers. | | **Focus and keyboard event scoping** | ✓ Scoped to iframe | In web component mode, keyboard shortcuts registered by the module (for example, Angular hotkey services) capture events on the host `document`. In iframe mode, keyboard events are naturally scoped to the iframe's document. | | **`setTimeout`/`setInterval` isolation** | ✓ Scoped to iframe context | Timers created by the module in web component mode run on the host `window`. If the host clears all timers (common in SPA route transitions), module timers are destroyed. Iframe timers are independent. | --- **Changelog** | Date | Change | | --- | --- | | 2026-06-10 | Compliance pass: added period to "vs." in two headings; changed "shows" to "displays"; fixed British spelling "initialises" in diagram note; converted Auto-Resize numbered list to bullets and moved non-mechanism items to prose; fixed subject-verb agreement in Feature Comparison intro; replaced "payloads" (jargon) with "data inputs"; fixed "The following table" to "The following sections" in Centauri Compatibility intro; changed "appear" to "display" in DynamicGrid row; changed "in" to "in" in Signature row; fixed sentence starting with inline code in EmbedDisplayController section. Readability: simplified "message-passing protocol" to "messaging system"; replaced "implements defense-in-depth" with plain-language description; replaced "orchestrates" with "manages". Rewrote "Components with Known Limitations in Web Component Mode" intro to clearly state all listed components work in iframe mode; removed redundant "Works in Iframe" column from the table. | | 2026-06-09 | Editorial pass: updated metadata title to match H1, rewrote introduction for 9th-grade readability, removed all HR dividers between sections, fixed heading em dashes (colon substitution), fixed British spellings throughout (defence → defense, behaviour/behaviours → behavior/behaviors, sanitisation → sanitization, initialising → initializing), replaced all "through" with "through" or equivalent, added why-descriptions to all sections lacking prose intros, expanded table descriptions for non-experts, renamed behavioral headings to American English, updated See Also links (architecture reference to published path, added landing page link). | | 2026-04-21 | Initial publication. | The UI (user interface) is a device's end-user interaction and communication point. It can include display screens, keyboards, and mouse. It is also how a user interacts with your application. The Shadow DOM is a web standard that allows you to create encapsulated, hidden DOM subtrees for your web components. It provides a way to scope CSS styles and JavaScript behavior within a component, preventing them from leaking out and interfering with the rest of the page. Cascading Style Sheets (CSS) is a style sheet language used for presenting how a HTML or XML document looks to end-users. JavaScript is an object-oriented computer programming language. It is most-commonly used for interactive effects in the browser. The Centauri (v 1.0.0) runtime is the first-generation foundation of the Unqork Designer Platform. Centauri provides Creators a codeless experience for developing applications. The Vega (v 2.0.0) runtime is the next-generation engine of the UDesigner platform. Vega uses cutting-edge technologies to improve the Creator and end-user experience. The Document Object Model (DOM) is the data representation of objects that form the structure and content of a document on the web. The DOM represents the page. APIs (application programming interfaces) are a set of protocols and definitions developers use to build and integrate application software. APIs act as the connective tissue between products and services. AngularJS is a JavaScript framework added to an HTML page with a