mountly
Framework components. Any page. On demand.
mountly turns React, Vue, Svelte, and TSRX components into lazy,
HTML-addressable features. Drop them into CMS pages, marketing sites, legacy apps,
partner embeds, or framework migrations without a host-app rewrite. Light DOM is the default;
use shadow: true when you need hard style isolation.
Small core + explicit subpaths.
mountly keeps a small top-level core entry and exposes focused subpath imports (for example
mountly/attach, mountly/elements,mountly/shadow,
mountly/assets). In browser import-map hosts, map only the subpaths you use.
One primitive. Several high-value jobs.
You wrap a component as a mountable widget. mountly loads and activates it from plain HTML when the page signals intent. Marketing reuse, strangler-fig migration, island-style UI, and embeds run on this one runtime.
What you keep
- Normal React, Vue, Svelte, or TSRX components
- Existing CMS, static, legacy, or app host pages
- Current routing, query-string state, and deployment model
- Per-widget ownership by the component team
No new component authoring model. No full app rewrite.
What mountly adds
- HTML tags like
<signup-card> - Activation on idle, viewport, click, hover, media, or URL change
- Shadow-DOM style isolation and automatic CSS loading
- Module/data caching, teardown, and prop updates
A small runtime for component delivery, not an app platform.
Where the primitive pays off.
shared block. Not a micro-frontend control plane.Six ways to say “now”.
A trigger is the signal that moves a feature from idle to preload to
mount. Pick the one that matches user intent, or compose your own with a plugin.
requestIdleCallback to preload during quiet moments.One state machine, five states. The same shape on every framework.
Every feature moves through the same sequence regardless of trigger or framework. You hook into any phase, abort in flight, and unmount without leaks.
shadow: true).A widget. A feature. A trigger. Three lines you’ll write.
Components stay components. The adapter wraps them as widgets. You wire a feature in code, or declare it as an HTML tag.
import { createWidget } from "mountly-react";import SignupCard from "./SignupCard.tsx";import styles from "./SignupCard.css?inline";
// 1. Wrap a component as a framework-agnostic widgetexport default createWidget(SignupCard, { styles });import { createOnDemandFeature } from "mountly";
// 2. Add the on-demand lifecycle around a widgetconst signup = createOnDemandFeature({ moduleId: "signup-card", loadModule: () => import("./signup-card.js"), render: ({ mod, container, props }) => mod.mount(container, props),});
// 3. Attach it to a DOM trigger — preload on hover, mount on clicksignup.attach({ trigger: document.querySelector("#cta")!, preloadOn: "hover", activateOn: "click",});Styling: mountly loads CSS with the module and applies it before render, so no FOUC. Light DOM lets the host’s design system reach in; pass
shadow: truefor full isolation.
<signup-card trigger="viewport" props='{"plan":"pro"}'></signup-card>
<script type="module"> import { defineMountlyFeature } from "mountly";
defineMountlyFeature("/widgets/dist/index.js");</script>Composable with frameworks. Useful where framework boundaries end.
| Approach | Best at | Tradeoff | Complexity |
|---|---|---|---|
| Traditional SPA | One app owns every surface | Poor fit for CMS, legacy, or partner-hosted UI | Low |
| Framework code-splitting | Routes inside a single framework app | Does not standardize HTML drops or host-agnostic lifecycle | Medium |
| Microfrontend orchestrators | Independent apps with org-level ownership | Operationally heavy for component-sized features. Shared config blocks, runtime negotiation, build-time coupling. | High |
| Monorepo + npm libs | Same org, shared CI, lazy routes until clean break | Merge coordination; not for foreign hosts you cannot merge into | Low |
| Import-map widgets (mountly model) | Team-scalable widgets with zero orchestrator | Shared React version agreement; you own CDN/manifest workflow | Low |
| mountly | Component features in any HTML page | Not a router, SSR framework, or control plane | Low |
One runtime, four adapters, one optional design preset.
createWidget(Component, { styles }).mountly-vueVue adapter: createWidget(Component), lightweight createApp per container.mountly-svelteSvelte adapter: auto-detects v4 class API and v5 functional mount/unmount.mountly-tailwindOptional Tailwind v4 design preset. Tokens shared with the runtime.