useLongPress React hook in TypeScript
v1.0.0Added in 1.0.0
A React long press hook for touch screens: handlers that fire after a hold, cancel on scroll and swallow the click that follows.
Press and hold a message on a phone: it shrinks while you hold, then a reaction bar pops up and the phone buzzes where it can. Move your finger or scroll and nothing fires. With a mouse, right-click opens the same bar, or add mouse to pointerTypes in the playground to hold with the mouse too.
useLongPress is a free React hook in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add use-long-press, together with Motion presets.
Add to a project
Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add use-long-pressUsage
Import useLongPress from @/hooks/use-long-press.
import { useState } from "react"
import { useLongPress } from "@/hooks/use-long-press"
export function MessageBubble({ text }: { text: string }) {
const [menu, setMenu] = useState(false)
const longPress = useLongPress<HTMLDivElement>(() => setMenu(true))
return (
<div
{...longPress}
onContextMenu={(event) => {
// right-click with a mouse opens the same menu
longPress.onContextMenu(event)
event.preventDefault()
setMenu(true)
}}
className="select-none rounded-2xl bg-foreground/5 px-3 py-2 [-webkit-touch-callout:none]"
>
{text}
{menu && <span>Reactions</span>}
</div>
)
}API
onLongPress*(event: LongPressEvent<T>) => voiduseLongPress(onLongPress, options?): runs once the press has been held for delay ms. Gets the target element, the pointer position (clientX / clientY) and the pointer type.
delaydefault450numberHold time in ms before it fires. The default is gestures.longPress from lib/motion, shared by every long press in the library.
slopdefault8numberHow far in px the pointer may move before the press is cancelled, so scrolling a list never fires it (gestures.slop).
pointerTypesdefault"touch, pen"readonly ("touch" | "pen" | "mouse")[]Which pointers can long press. A mouse is left out by default because right-click does the same job there.
hapticsdefaulttruebooleanA 10ms vibration when it fires, on devices that support it (Android). Silently skipped elsewhere.
disableddefaultfalsebooleanIgnores every press.
onStart / onCancel / onFinish(event: LongPressEvent<T>) => void / () => void / () => voidA press began (start a holding style), ended before firing (released early, moved, scrolled), or the finger lifted after it fired.
returnsLongPressHandlers<T>onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onPointerLeave, onContextMenu and onClickCapture, to spread on the element (or on a Radix trigger through asChild, which merges them). Add select-none [-webkit-touch-callout:none] to the element so iOS shows no callout.
Parts
LongPressEvent
typeWhat onLongPress and onStart receive: { target, clientX, clientY, pointerType }.
UseLongPressOptions
typeThe options object: delay, slop, disabled, pointerTypes, haptics, onStart, onCancel and onFinish.
LongPressHandlers
typeThe returned pointer, context menu and click capture handlers to spread on the element.
LongPressPointerType
type"touch" | "pen" | "mouse", the values pointerTypes accepts.
Examples
Hold to confirm
A 1.2 second hold deletes; the fill grows while you press and resets if you let go.
Tap opens, hold selects
A photo grid where a long press enters selection mode and the click after it is swallowed.
Dependencies
Files
- hooks/use-long-press.ts
FAQ
Is the useLongPress hook free?
Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.
How do I install useLongPress?
Run npx wingo-ui@latest add use-long-press. It also adds the Wingo UI item it builds on (Motion presets). With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/use-long-press.json.