Skip to content

Quick start

The fastest path is the CLI. It scaffolds a React widget pre-wired with the build pipeline, both bundle outputs, and a working host page.

Terminal window
npx mountly init my-widget
cd my-widget

You get:

  • src/Component.tsx — a React component (you can swap in Vue or Svelte later).
  • A widget factory using mountly-react’s createWidget.
  • A tsup build that produces both dist/index.js (self-contained) and dist/peer.js (shared React).
  • An example host page.
Terminal window
pnpm install
pnpm build

Two 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.

host.html
<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. If you need full style isolation, pass shadow: true to createWidget.

Section titled “3b. Lowest-ceremony host (recommended for plain HTML)”

If you’re on a static/CMS host, prefer declarative islands + one script tag:

host.html
<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 still works when JS is unavailable.

mount() is the bare minimum. To get on-intent loading, wrap the widget in a feature:

page.ts
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 the sibling dist/index.css is fetched and applied automatically. The widget code is fetched on first hover and mounted on click. Open DevTools → Network and watch.

Need bespoke loading or rendering? loadModule and render are still available and override the auto-derived defaults.

The repo ships several runnable examples. The richest is the marketing site:

Terminal window
git clone https://github.com/jagreehal/mountly
cd mountly
pnpm install && pnpm -r build
cd examples/marketing-site && pnpm dev

Open http://localhost:5176/examples/marketing-site/. You’ll see:

  • A hero “Join the newsletter” button — preloads on hover, mounts on click.
  • An inline embed — mounts on viewport entry.
  • Zero framework JavaScript on the host before interaction.

The shortest copy-paste host lives at http://localhost:5175/examples/quickstart/host.html after running cd examples/plain-html && pnpm dev.