on-long-press
Call a handler when an element is pressed and held.
| Package | @vizejs/composable/on-long-press |
| Own the source | vize lib pull composable:on-long-press |
| Runtime exports | onLongPress |
| Gzip budget | 2560 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { onLongPress } from "@vizejs/composable/on-long-press";
Try it
Reveal a review note before releasing a held button
Deliver a bounded long-press action through real pointer events while retaining ordinary native button activation for the same note.
What to observe: Hold Reveal review note for 500 ms: it opens before release and the long-press counter increments once. An early release or movement beyond 10 pixels cancels that delivery. An ordinary click, tap, or Enter still reveals the note independently. Stop long-press observation removes held actions; the native reveal and hide buttons continue working.
onLongPress watches the real native button ref and receives the initiating PointerEvent. The example records its pointerType and native release summary separately from the ordinary click handler. Only the timed handler increments the long-press count. Its release duration comes from the real default Date.now clock; distance is measured from the initiating coordinates. Moving beyond the threshold, leaving, cancelling, or releasing clears pending delivery, and stop removes listeners and the timer. The last release summary stays explicitly last-observed after stop. During SSR there is no target and no timer starts. The scope also disposes the registration. No custom pointer host or scheduler is supplied.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { ref, useTemplateRef } from "vue";
import { onLongPress } from "@vizejs/composable/on-long-press";
const reveal = useTemplateRef<HTMLButtonElement>("reveal");
const details = ref(false);
const deliveries = ref(0);
const pointer = ref("none");
const release = ref("No pointer release recorded.");
const stopped = ref(false);
const stop = onLongPress(
reveal,
(event) => {
deliveries.value += 1;
pointer.value = event.pointerType;
details.value = true;
},
{
delay: 500,
distanceThreshold: 10,
onRelease: (result) => {
release.value = `Last pointer release: long press ${result.isLongPress ? "yes" : "no"} · ${Math.round(result.duration)} ms · ${Math.round(result.distance)} pixels.`;
},
},
);
function stopObservation(): void {
stop();
stopped.value = true;
}
</script>
<template>
<div class="composable-example">
<button ref="reveal" type="button" :aria-expanded="details" @click="() => (details = true)">
Reveal review note
</button>
<p v-if="details">Check the deployed keyboard path before calling a fix delivered.</p>
<div class="example-actions">
<button type="button" @click="() => (details = false)">Hide review note</button>
<button type="button" :disabled="stopped" @click="stopObservation">
Stop long-press observation
</button>
</div>
<output aria-live="polite"
>Long-press deliveries: {{ deliveries }} · Last pointer: {{ pointer }}</output
>
<p>{{ release }}</p>
<p>
Hold Reveal review note for 500 ms to reveal it before release. Releasing early or moving more
than 10 pixels cancels long-press delivery. An ordinary click, tap, or Enter on the same
button independently reveals the note; the long-press count records only the held action.
</p>
<p v-if="stopped">
Long-press observation stopped. The native reveal and hide controls still work.
</p>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
onLongPress |
input | experimental | deterministic-fallback | stable | caller, reactive-scope | web, desktop | globalThis |
resolveElement, tryOnScopeDispose |
API
onLongPress
Call a handler when an element is pressed and held. Uses Pointer Events, so mouse, touch, and pen behave alike. Moving more than distanceThreshold or releasing early cancels the press. Nothing is registered during server rendering; listeners and the timer are released with the owning scope or the returned stop function.
function onLongPress( target: MaybeElementTarget, handler: (event: PointerEvent) => void, options: OnLongPressOptions = {}, ): () => void
Types
LongPressModifiers
Event modifiers applied to the pointer events handled by onLongPress.
| Member | Type | Description |
|---|---|---|
stop? |
boolean |
Call stopPropagation(). |
once? |
boolean |
Fire at most once. |
prevent? |
boolean |
Call preventDefault(). |
capture? |
boolean |
Listen in the capture phase. |
self? |
boolean |
Only start when the element itself (not a descendant) is pressed. |
LongPressRelease
Summary passed to OnLongPressOptions.onRelease.
| Member | Type | Description |
|---|---|---|
duration |
number |
Milliseconds between press and release. |
distance |
number |
Pointer travel in CSS pixels. |
isLongPress |
boolean |
Whether the long-press handler fired. |
OnLongPressOptions
Options for onLongPress.
| Member | Type | Description |
|---|---|---|
delay? |
number |
Hold time in milliseconds. |
distanceThreshold? |
number |
Maximum pointer travel before the press is cancelled. |
modifiers? |
LongPressModifiers |
Event modifiers. |
onRelease? |
(release: LongPressRelease, event: PointerEvent) => void |
Called on every release with timing details. |
now? |
() => number |
Clock for durations. |
scheduler? |
TimeoutScheduler |
Owns the hold timer. |