Vize

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.

Open the interactive example

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
Reveal a review note before releasing a held button: initial state
Initial state
Reveal a review note before releasing a held button: state after the verified interactions
After the verified interactions

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.