Svelte
mountly-svelte is the Svelte adapter. It supports both Svelte 4 (legacy class component API) and Svelte 5 (functional component API), and auto-detects which one your component uses.
Install
Section titled “Install”pnpm add mountly mountly-svelte svelteSvelte 4
Section titled “Svelte 4”If you’re on Svelte 4, the adapter detects the legacy class API and uses new Component({ target, props }) internally. No extra setup.
import { createWidget } from "mountly-svelte";import SignupCard from "./SignupCard.svelte";
export default createWidget(SignupCard);The Vite library build emits dist/index.js plus dist/index.css (Svelte’s component styles, hashed). The adapter fetches the CSS automatically when the host wires up moduleUrl; see “On-demand lifecycle (zero-config)” below.
Svelte 5
Section titled “Svelte 5”Svelte 5 components are plain functions. Pass mount and unmount from "svelte":
import { createWidget } from "mountly-svelte";import { mount, unmount } from "svelte";import SignupCard from "./SignupCard.svelte";
export default createWidget(SignupCard, { mount, unmount });If you omit them, the adapter dynamically imports "svelte" itself. That works, but adds one promise hop on first mount.
Mounting
Section titled “Mounting”import widget from "./signup-card.js";
widget.mount(document.querySelector("#cta-mount"), { headline: "Try the API",});Each mount() unmounts any existing instance in the same container first.
On-demand lifecycle (zero-config)
Section titled “On-demand lifecycle (zero-config)”import { createOnDemandFeature } from "mountly";
const signup = createOnDemandFeature({ moduleId: "signup-card", moduleUrl: "/widgets/signup-card/dist/index.js",});
signup.attach({ trigger: btn, preloadOn: "hover", activateOn: "click" });mountly threads moduleUrl through to the adapter, which fetches dist/index.css (sibling) and applies it before render. No FOUC, no manual loader. Default light DOM lets the host’s design system reach in; pass shadow: true for hard isolation.
Need to override? loadModule / render still work and trump the auto-derived defaults.
Live updates
Section titled “Live updates”The Svelte adapter falls back to remount on feature.update(), which preserves the container but creates a new component instance — local state inside the component resets. If you need state to survive a prop change, lift it to a store or pass it back in via props.
Common pitfalls
Section titled “Common pitfalls”Two Svelte runtimes on the same page
Section titled “Two Svelte runtimes on the same page”Same risk as React/Vue. Use the peer build pattern for multi-widget pages — externalise svelte and provide it once via the host’s import map.
Style isolation
Section titled “Style isolation”Svelte’s component-scoped styles already isolate via Svelte’s hash. With shadow: true they get an additional hard boundary. Global styles (:global(...)) inside a Svelte component land inside the shadow tree when shadow: true (so they don’t leak to the document); in default light DOM they reach the document, which is usually what you want.
Reference
Section titled “Reference”createWidget— the adapter API.createOnDemandFeature— the lifecycle wrapper.
Tailwind and non-Tailwind defaults
Section titled “Tailwind and non-Tailwind defaults”No Tailwind
Section titled “No Tailwind”The Vite + @sveltejs/vite-plugin-svelte library build emits a sibling dist/index.css for any component that has <style>. The adapter picks it up automatically when the host passes moduleUrl:
import { createWidget } from "mountly-svelte";import Component from "./Component.svelte";
export default createWidget(Component);With Tailwind
Section titled “With Tailwind”Compile Tailwind into the same dist/index.css (via your build’s CSS entry) and the same zero-config flow applies. If your Tailwind output lives at a non-default path, point the host at it explicitly:
createOnDemandFeature({ moduleId: "card", moduleUrl: "/widgets/card/dist/index.js", // No assetOptions needed; adapter derives /widgets/card/dist/index.css.});If you’d rather inline the CSS string at build time (e.g. small components, no shared Tailwind layer), that path still works:
import { createWidget } from "mountly-svelte";import Component from "./Component.svelte";import styles from "./styles.css?inline";
export default createWidget(Component, { styles });