Quick start
The CLI is the fastest path. It scaffolds a React widget pre-wired with the build pipeline, both bundle outputs, and a working host page.
Not sure mountly is the right tool? Read Choosing an architecture first — most teams should start with a monorepo npm lib, not micro frontends.
1. Scaffold a widget
Section titled “1. Scaffold a widget”npx mountly init my-widgetcd my-widgetYou get:
src/Component.tsx: a React component (you can swap in Vue or Svelte later).- A widget factory using
mountly-react’screateWidget. - A
tsupbuild that produces bothdist/index.js(self-contained) anddist/peer.js(shared React). - An example host page.
2. Install and build
Section titled “2. Install and build”pnpm installpnpm buildTwo artifacts land in dist/:
index.js: self-contained bundle. Includes React. Drop into any page.peer.js: peer build. Excludes React. Use when the host already maps React via an import map.
See Distribution for which one to ship.
3. Mount it
Section titled “3. Mount it”<div id="mount"></div><script type="module"> import widget from "./my-widget/dist/index.js"; widget.mount(document.getElementById("mount"));</script>The widget mounts inside the container in light DOM and the host’s CSS reaches in. For full style isolation, pass shadow: true to createWidget.
3b. Lowest-ceremony host (recommended for plain HTML)
Section titled “3b. Lowest-ceremony host (recommended for plain HTML)”On a static or CMS host, prefer declarative islands plus one script tag:
<div data-mountly-island='{"schemaVersion":1,"id":"signup","moduleId":"signup-card","trigger":"idle","props":{"plan":"pro"}}'> <a href="/signup">Sign up (fallback)</a></div>
<script type="module" src="/packages/mountly/dist/host-entry.js" data-mountly-host data-mountly-loaders='{"signup-card":"/widgets/signup-card.js"}'></script>This is the default DX path: no host app code, one script tag, and fallback HTML that still works when JS is unavailable.
4. Add the on-demand lifecycle
Section titled “4. Add the on-demand lifecycle”mount() is the bare minimum. For on-intent loading, wrap the widget in a feature:
import { createOnDemandFeature } from "mountly";
const signup = createOnDemandFeature({ moduleId: "signup-card", moduleUrl: "./my-widget/dist/index.js",});
signup.attach({ trigger: document.querySelector("#cta")!, preloadOn: "hover", activateOn: "click",});mountly synthesises the loader and a default render that threads moduleUrl through to the adapter, so it fetches and applies the sibling dist/index.css for you. It fetches the widget code on first hover and mounts it on click. Open DevTools → Network and watch.
For bespoke loading or rendering, loadModule and render are still available and override the auto-derived defaults.
5. See the full demo
Section titled “5. See the full demo”Try the hosted demos — no clone required:
- Quickstart host — hover to preload, click to mount.
- Marketing site — hero button + viewport embed.
The marketing site shows hover preload, click mount, and viewport-triggered embeds with zero host framework JS before interaction.
Run locally (optional):
git clone https://github.com/jagreehal/mountlycd mountlypnpm install && pnpm -r buildcd docs/examples/plain-html && pnpm devThen open http://localhost:5175/docs/examples/quickstart/host.html.
Where to next
Section titled “Where to next”- How it works: the architecture in one page.
- Triggers: the six ways to say “now”.
- React / Vue / Svelte: adapter-specific patterns.
- API:
createOnDemandFeature: the core primitive.