Skip to content

Trigger plugins

The five built-in triggers (hover, click, focus, viewport, idle) cover most cases. For the rest, mountly ships a small trigger plugin API and four ready-made plugins.

import {
registerTriggerPlugin,
unregisterTriggerPlugin,
getTriggerPlugin,
getAllTriggerPlugins,
createPluginTrigger,
registerBuiltInPlugins,
// Built-ins:
createSwipeTrigger,
createLongPressTrigger,
createKeyboardTrigger,
createUrlChangeTrigger,
} from "mountly";

createSwipeTrigger(element, callback, options?)

Section titled “createSwipeTrigger(element, callback, options?)”

Touch swipe gesture detection. Returns a cleanup function.

const cleanup = createSwipeTrigger(panelElement, () => panelFeature.activate(), {
direction: "left",
threshold: 60,
});
Option Type Default Notes
direction "up" · "down" · "left" · "right" "left" Required swipe direction.
threshold number px 40 Minimum distance for a swipe.
velocity number px/ms 0.3 Minimum velocity.

createLongPressTrigger(element, callback, options?)

Section titled “createLongPressTrigger(element, callback, options?)”

Mouse / touch long-press. Cancels on movement past tolerance px.

const cleanup = createLongPressTrigger(contextMenuTarget, () => menuFeature.activate(), {
duration: 600,
tolerance: 8,
});
Option Type Default Notes
duration number ms 500 Hold time before firing.
tolerance number px 10 Cancel if pointer moves further than this.

Single key or chord shortcut. Listens at the document level.

const cleanup = createKeyboardTrigger(
() => commandPaletteFeature.activate(),
{ key: "k", meta: true }, // Cmd+K / Ctrl+K
);
Option Type Default Notes
key string required Matches event.key.
meta boolean false Require Meta on macOS, Ctrl on others.
shift boolean false Require Shift.
alt boolean false Require Alt.
preventDefault boolean true Call event.preventDefault() on match.

createUrlChangeTrigger(element, callback, options?)

Section titled “createUrlChangeTrigger(element, callback, options?)”

Listens for URL changes and fires when one matches.

const cleanup = createUrlChangeTrigger(pageContainer, () => billingFeature.activate(), {
events: ["popstate", "pushstate"],
});
Option Type Default Notes
events ("popstate" | "hashchange" | "pushstate" | "replacestate")[] all four Which URL events to listen for.

A trigger plugin is an object that knows how to wire and unwire itself for an element.

interface TriggerPlugin {
name: string;
setup(
element: HTMLElement,
onTrigger: (ctx: TriggerContext) => void,
options?: Record<string, unknown>,
): () => void;
}

Register with registerTriggerPlugin:

registerTriggerPlugin({
name: "double-tap",
setup(element, onTrigger, options) {
let lastTap = 0;
const handler = () => {
const now = Date.now();
if (now - lastTap < (options?.window ?? 300))
onTrigger({ element, triggerType: "programmatic" });
lastTap = now;
};
element.addEventListener("pointerup", handler);
return () => element.removeEventListener("pointerup", handler);
},
});

Then wire it via createPluginTrigger:

const cleanup = createPluginTrigger("double-tap", element, () => feature.activate(), {
window: 250,
});
getTriggerPlugin("double-tap"); // → TriggerPlugin | undefined
getAllTriggerPlugins(); // → TriggerPlugin[]
unregisterTriggerPlugin("double-tap");

Convenience to register the four shipped plugins under a known set of names. Call once if you want them discoverable via getTriggerPlugin. The standalone createSwipeTrigger etc. work without it.

  • Triggers: the conceptual overview, including the built-in five.