Skip to content

Triggers

A trigger is the signal that moves a feature between states. mountly ships seven built-in trigger modes in attach() and lets you register more as plugins.

You almost never call the trigger setup directly. Instead, you describe intent through feature.attach({ preloadOn, activateOn }) and the runtime wires the right listeners for you.

Preloads on mouseenter, mounts on click. The default for discoverable controls — buttons, menu items, link previews. The 100 ms delay before fire suppresses fly-over hovers; if the user leaves before the delay elapses, the load is cancelled.

feature.attach({ trigger: btn, preloadOn: "hover", activateOn: "click" });

Mounts on click without preloading. Use when intent is committed rather than exploratory — modal openers, save buttons, anything where you’d rather pay the load cost on click than on every passing hover.

feature.attach({ trigger: btn, preloadOn: false, activateOn: "click" });

Preloads on focus, mounts on commit. The keyboard counterpart to hover — pair both so mouse and keyboard users get parity.

feature.attach({ trigger: input, preloadOn: "hover", activateOn: "focus" });

Mounts when the trigger element enters the viewport. Backed by IntersectionObserver with a configurable threshold (default 0.1). The default for below-the-fold widgets — analytics dashboards, embedded media, anything the user might never scroll to.

feature.attach({ trigger: section, preloadOn: "viewport", activateOn: "viewport" });

Uses requestIdleCallback to preload during quiet moments. Use sparingly — every idle preload is bytes the user might never need. Pair with predictive prefetch for the smarter version that scores against interaction history.

feature.attach({ trigger: el, preloadOn: "idle", activateOn: "click" });

You can also mount on idle directly (Astro-like client:idle behavior):

feature.attach({ trigger: el, preloadOn: false, activateOn: "idle", idleTimeout: 500 });

Mounts when a CSS media query matches (Astro-like client:media).

feature.attach({
trigger: el,
preloadOn: false,
activateOn: "media",
activateOnMediaQuery: "(max-width: 50em)",
});

Mounts when the URL matches a pattern. Listens to popstate, hashchange, and (via patched method) pushState / replaceState. Useful for route-driven content in non-SPA hosts.

feature.attach({
trigger: container,
activateOn: "url-change",
activateOnUrlEvents: ["popstate", "pushstate"],
});

The two stages are independent. You can preload aggressively but mount conservatively, or vice versa.

GoalpreloadOnactivateOn
Discoverable button"hover""click"
Form-only action"hover""focus"
Below-fold reveal"viewport""viewport"
Below-fold with early wakeup"viewport" + viewportRootMargin: "200px""viewport"
Below-fold but only after explicit interest"viewport""click"
Route-driven panel"idle""url-change"
Responsive-only widgetfalse"media"
Idle auto-mountfalse"idle"
Fully imperativefalse(you call feature.mount yourself)

By default attach() toggles: a second activateOn event unmounts the feature. Set toggle: false for one-way mount.

feature.attach({ trigger: btn, activateOn: "click", toggle: false });

Hover, focus, and idle all cancel automatically if the user backs out before the delay fires (mouseleave, blur, idle slot withdrawn). Once a request is in flight, you can abort it manually:

feature.abort();
// state → "aborted", any in-flight load DOMException("AbortError")s

Anything not covered by the built-ins can be added as a plugin. Three are provided out of the box:

  • createSwipeTrigger — touch swipe gestures.
  • createLongPressTrigger — touch / mouse long-press.
  • createKeyboardTrigger — single keys or chord shortcuts.

See Trigger plugins for the full API and how to register your own.

Skip attach() entirely and drive the feature programmatically:

await feature.preload(); // start the load when you want
await feature.activate(); // commit once data is ready
const handle = await feature.mount(container, context, props);
// later:
handle.unmount();

Use this when the host owns timing (route changes, server-driven flags, wizard steps, batch operations).

mountly can match Astro’s client-side timing directives (load, idle, visible, media) at runtime.

It does not implement Astro compile-time/server directives (client:only, server:defer, set:html, is:inline, etc.), which belong to Astro’s compiler/runtime model.