Custom triggers
A trigger decides when an island loads and mounts. Eight ship with the core, and adding a ninth takes one line — there is no plugin API to learn, because the trigger table is already the registry.
The built-in triggers
Section titled “The built-in triggers”Each reads as kind or kind:arg, so a trigger never needs a second attribute
to hold its argument.
data-on / data-preload |
Argument | Fires when |
|---|---|---|
click |
— | The island is clicked |
focus |
— | Focus lands inside it (focusin, so children count) |
hover |
Delay in ms, default 100 |
The pointer settles over it |
viewport |
rootMargin, default 0px |
It intersects the viewport |
idle |
Timeout in ms | The browser goes idle (requestIdleCallback) |
media |
A media query | The query matches, now or later |
url |
— | popstate, hashchange, pushState or replaceState |
never |
— | Only when code calls mount(el) |
<button data-mountly="/w.js" data-on="click focus">Any of them fires</button><div data-mountly="/w.js" data-on="media:(min-width: 60rem)"></div><div data-mountly="/w.js" data-on="viewport:200px"></div><div data-mountly="/w.js" data-preload="hover:300"></div>Adding your own
Section titled “Adding your own”triggers is a plain object of (element, arg, run) => teardown. Assign to it
before mountly() runs.
import { mountly, triggers } from "mountly";
triggers["double-tap"] = (el, windowMs, run) => { let last = 0; const handler = () => { const now = performance.now(); if (now - last < (Number(windowMs) || 300)) run(); last = now; }; el.addEventListener("pointerup", handler); return () => el.removeEventListener("pointerup", handler);};
mountly();<div data-mountly="/w.js" data-on="double-tap:250"></div>run may fire many times — the core ignores repeats once the island is
mounted (unless data-toggle is set), so a trigger does not need to
de-duplicate. Return a teardown that removes whatever you attached; the core
calls it when the island is torn down.
An unknown data-on kind is an error, not a silent no-op: the island lands in
data-mountly-state="error" and dispatches mountly:error.
Gestures
Section titled “Gestures”mountly/gestures ships swipe, long-press and keyboard-shortcut primitives in
the same handler-plus-teardown shape, so wiring one up as a trigger is a
forwarding call.
import { triggers } from "mountly";import { eachSwipe, eachLongPress, eachKeyboard } from "mountly/gestures";
triggers.swipe = (el, direction, run) => eachSwipe(el, run, { direction: direction as "up" | "down" | "left" | "right" });
triggers.longpress = (el, duration, run) => eachLongPress(el, run, { duration: Number(duration) || undefined });
triggers.hotkey = (_el, key, run) => eachKeyboard(run, { key, meta: true });<div data-mountly="/drawer.js" data-on="swipe:left"></div><div data-mountly="/menu.js" data-on="longpress:600"></div><div data-mountly="/palette.js" data-on="hotkey:k"></div>They are kept out of the core because most pages never need them: the core is
2.3 KB, and importing mountly/gestures is what decides whether swipe
detection ships to your users.
| Primitive | Signature | Options |
|---|---|---|
eachSwipe |
(el, handler, opts?) |
direction ("left" default), threshold px (40), velocity px/ms (0.3) |
eachLongPress |
(el, handler, opts?) |
duration ms (500), tolerance px (10) |
eachKeyboard |
(handler, opts) |
key (required), meta, shift, alt, preventDefault |
Each also has a one-shot promise form — onSwipe, onLongPress, onKeyboard —
for await-style code outside the island lifecycle.