npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mountly

v1.0.1

Published

**On-Demand Interactive UI Platform**

Readme

mountly

On-Demand Interactive UI Platform

Load rich UI only when the user needs it. Use your existing React, Vue, or Svelte components with no new component model. Modernize legacy pages incrementally without rewriting the host app.

Documentation: https://jagreehal.github.io/mountly

Two ways in

Building a web app? Load widgets on user intent — hover, click, viewport, idle — so the page ships a shell instead of everything. → Quick start

Building an MCP server? Turn a React, Vue or Svelte component into an MCP Apps (SEP-1865) view that renders inside Claude and ChatGPT.

npx mountly-mcp create my-app --framework react
cd my-app && pnpm install && pnpm dev

Agent Skills · MCP Apps quick start · Mountly vs ext-apps · mountly-mcp

Both sit on the same widget model, so a component written for one works in the other. For MCP Apps, prefer the mountly-mcp docs. You do not need the islands API to ship a View.

The Problem

Modern web apps ship too much JavaScript upfront. Component libraries load everything at once. Microfrontends are operationally heavy. Framework lazy-loading lacks standardized interaction patterns.

No unified system covers: "Load rich UI only when the user needs it."

What mountly Does

mountly is a frontend platform for building Features, Widgets that load on user intent (hover, click, focus, viewport entry, or idle time).

Before mountly:                    After mountly:
┌──────────────────────┐            ┌──────────────────────┐
│  Full app JS bundle  │            │  Page shell (light)  │
│  - Payment widget    │            │                      │
│  - Video player      │────►       │  [User hovers]       │
│  - Image lightbox    │            │  → Load widget code  │
│  - Analytics panel   │            │  → Fetch data        │
│  - Chat widget       │            │  → Mount UI          │
└──────────────────────┘            └──────────────────────┘
  Slow TTI, heavy bundle              Fast TTI, lean bundle

Key Features

  • Intent-driven loading: code splits at the feature level, loads on hover/click/focus/viewport/idle/url-change
  • Dual caching: module cache (JS code) plus data cache (API responses) with in-flight deduplication
  • Framework-agnostic core: the runtime is framework-agnostic. React, Vue, and Svelte adapters today; Solid in the same shape later.
  • Standardized lifecycle: idle → preload → activate → mount → unmount
  • Multiple instances: mount the same feature multiple times on one page
  • Small core: 2.3 KB gzipped, one file, no dependencies; widgets load on demand, not on page load
  • Custom element: <mountly-feature> web component for declarative usage
  • Isolation when you need it: light DOM, shadow DOM, or a cross-origin iframe — the host chooses, the widget source does not change
  • Analytics: built-in interaction timing and performance tracking
  • Predictive prefetch: idle-time loading scored by interaction history
  • Extensible triggers: eight built in; add swipe, long-press or a keyboard chord with one assignment to the triggers table
  • Devtools panel: floating debug UI showing live feature states and events

Packages

| Package | Purpose | | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | mountly | Core runtime, on-demand loader, lifecycle, custom element, CLI | | mountly-react | React adapter, createWidget(Component, { styles }) | | mountly-vue | Vue adapter, createWidget(Component, { styles }) | | mountly-svelte | Svelte adapter, createWidget(Component, { styles }) | | mountly-tailwind | Tailwind v4 design preset (opt-in) | | mountly-vite-plugin | Vite lib build plugin, dual index.js / peer.js widget output | | mountly-manifest | Vertical registry schema, import map + host helpers | | mountly-mcp | MCP Apps (SEP-1865) — build views from React, Vue or Svelte components. Subpaths: ./react, ./vue, ./svelte, ./vite, ./server, ./json-render |

Build with Agent Skills

The fastest way to build an MCP App View is to let your coding agent do it. Install the Mountly skills once, then ask:

| Skill | What it does | Try it | | ---------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------- | | create-mcp-app | Scaffolds via mountly-mcp create | "Create an MCP App" | | add-app-to-server | Adds Views to an existing server | "Add UI to my MCP server" | | convert-web-app | Wraps an existing component | "Turn my component into an MCP App" | | migrate-ext-apps | Migrates official ext-apps Views | "Migrate from ext-apps" |

/plugin marketplace add jagreehal/mountly
/plugin install mountly-mcp@mountly

Or: npx skills add jagreehal/mountly · full install notes: Agent Skills.

Build an MCP App from a component you already have

MCP Apps (SEP-1865) lets an MCP server render interactive UI inside Claude, ChatGPT and other hosts. Mountly MCP is the View kit. New dashboards and existing website components use the same path:

import { createMcpView } from "mountly-mcp/vue";
import Dashboard from "./Dashboard.vue";

createMcpView(Dashboard);

Greenfield without an agent:

npx mountly-mcp create my-app --framework react

Add mountlyMcpViews() to your Vite config and npx mountly-mcp build emits the ui:// resource plus its sidecar. Then develop it against a real host — sandbox proxy, CSP, the full handshake — without installing one:

npx mountly-mcp dev --server ./server.js

registerMcpApps(server, { views, tools }) installs the result into an MCP server you own, so transport, auth and deployment stay yours. The wire protocol is delegated to the official @modelcontextprotocol/ext-apps SDK, so it tracks the spec rather than reimplementing it.

Agent Skills · MCP Apps quick start · protocol harness demo

Quick Start (60 seconds)

An island is a URL, a trigger, and some props. Write it in HTML; there is no JavaScript for you to write.

<button data-mountly="/widgets/cart.js" data-preload="hover" data-target="#panel">
  Basket (3)
</button>
<div id="panel"></div>

<script type="module" src="https://unpkg.com/mountly/dist/auto.js"></script>

Hovering the button downloads cart.js (and its sibling cart.css); clicking mounts it into #panel. Until then the page ships the button and nothing else.

/widgets/cart.js is any module with a mount:

export default {
  mount(el, props) {
    /* React, Vue, Svelte, or plain DOM */
  },
  unmount(el) {},
};

The three adapters produce exactly this shape from a component you already have:

import { createWidget } from "mountly-react";
import Cart from "./Cart";

export default createWidget(Cart);

See it running: clone the repo, run pnpm install && pnpm -r build && cd docs/examples/plain-html && pnpm dev, then open http://localhost:5175/docs/examples/quickstart/host.html (source). Or try the hosted quickstart — no clone required.

The attributes

| Attribute | Default | What it does | | -------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | data-mountly | — | Module URL, or a key in the host script's data-mountly-urls map | | data-on | click | When to mount. click focus fires on whichever comes first | | data-preload | — | When to fetch without mounting — usually hover or viewport | | data-props | {} | JSON props. A <script type="application/json"> child works too, when quotes get awkward | | data-target | the element | Where to mount, if not the trigger itself | | data-toggle | off | A second activation unmounts instead of doing nothing | | data-css | sibling .css | none, or an explicit stylesheet URL | | data-mountly-state | — | idle / loading / mounted / error, so CSS can style each. Server-render it as mounted and mountly leaves the island alone |

Triggers read as kind or kind:arghover:300, viewport:200px, media:(min-width: 60rem), idle:2000. click, focus, url and never take no argument.

When HTML is not enough

import { mountly, mount, unmount, update } from "mountly";

const stop = mountly({
  urls: { cart: "/widgets/cart.js" },
  // the one escape hatch: retries, auth headers, a bundler's own import(),
  // a test double — instead of an attribute for each
  load: (url) => fetch(url).then(/* ... */),
});

mountly() also watches the DOM, so islands rendered later — by another widget, by htmx, by a Turbo frame swap — wire themselves up with no ordering knob to configure.

Going further

API Stability

mountly is 1.0. The surface below follows semver: additions ship in minor releases, breaking changes wait for 2.0.

  • the data-* island attributes and data-mountly-state
  • mountly() / mount / unmount / update / wire / triggers
  • adapter contract types (WidgetModule, AdapterOptions)
  • installRuntime shape (including react/jsx-runtime mapping support)

Migrating from an earlier release? See the changelog.

Releases follow docs/release-checklist.md.

SSR

Render the island's markup on the server and set data-mountly-state="mounted". mountly skips it — no double paint, no client mount, and the markup stays styled if JavaScript never arrives. That one attribute is the whole handshake.

<div data-mountly="/widgets/cart.js" data-mountly-state="mounted">
  <!-- server-rendered markup -->
</div>

Anything inside an island before it mounts is its fallback: a link, a static summary, a skeleton. Reserve space with style="min-height: 40px" — no mountly attribute needed, CSS already does this.

Examples

See docs/examples/README.md for start order, ports, and when to use each pattern.

Summary:

  • docs/examples/payment-breakdown: a popover with async data loading and shadow-DOM styling
  • docs/examples/image-lightbox: a media viewer with focus restoration
  • docs/examples/signup-card: a marketing card
  • docs/examples/demo: a Vite host that exercises all of the above
  • docs/examples/plain-html: bundler-free integration via import maps
  • docs/examples/marketing-site: embedding widgets in static HTML
  • docs/examples/quickstart/host.html: minimal import map + attach() host
  • docs/examples/pokemon-kitchen-sink: stress-test of all features

Development

pnpm install
pnpm -r build
pnpm test

License

MIT