Skip to content

createWidget

import { createWidget } from "mountly-react"; // or "mountly-vue" / "mountly-svelte"

Turns a component into a framework-agnostic widget — an object with mount(container, props) and unmount(container) that mountly’s runtime can drive.

The signature is intentionally identical across adapters.

function createWidget<P>(
Component: ComponentType<P>,
options?: AdapterOptions
): WidgetModule;
FieldTypeNotes
stylesstringCSS to inject into the widget’s shadow root.
mode"open" · "closed"Shadow root mode. Default "open".
delegatesFocusbooleanForward to attachShadow.

Required when the component is Svelte 5:

FieldTypeNotes
mount<P>(C, opts) => Record<string, unknown>Pass mount from "svelte".
unmount(handle) => void | Promise<void>Pass unmount from "svelte".

Svelte 4 components need neither — the adapter detects the legacy class and uses new Component({ target, props }).

interface WidgetModule {
mount(container: HTMLElement, props: Record<string, unknown>): void;
unmount(container: HTMLElement): void;
// React adapter also exposes:
// update?(container, props): void;
}
import { createWidget } from "mountly-react";
import SignupCard from "./SignupCard.tsx";
import styles from "./SignupCard.css?inline";
export default createWidget(SignupCard, { styles });

The React adapter exposes update() automatically — feature.update(container, props) reuses the same React root, preserving hooks state.

import { createWidget } from "mountly-vue";
import SignupCard from "./SignupCard.vue";
import styles from "./SignupCard.css?inline";
export default createWidget(SignupCard, { styles });

One Vue app per container. Two widget mounts = two Vue apps; providers don’t cross.

import { createWidget } from "mountly-svelte";
import SignupCard from "./SignupCard.svelte"; // Svelte 4 class component
import styles from "./SignupCard.css?inline";
export default createWidget(SignupCard, { styles });
import { createWidget } from "mountly-svelte";
import { mount, unmount } from "svelte";
import SignupCard from "./SignupCard.svelte"; // Svelte 5 functional component
import styles from "./SignupCard.css?inline";
export default createWidget(SignupCard, { styles, mount, unmount });

If you forget mount / unmount on a v5 component, you’ll see:

[mountly-svelte] Svelte 5 component detected but `mount`/`unmount` options were not provided.

All adapters call attachShadow(container, options) internally. This means:

  • Styles in options.styles are injected into the shadow root and don’t leak out.
  • The host’s CSS doesn’t bleed in (modulo CSS custom properties, which inherit through shadow roots intentionally).
  • The container itself stays as the shadow host; the widget renders into the shadow tree.

If you want to mount into a non-shadow element (advanced, breaks isolation), implement your own widget shape — WidgetModule is just an interface.