useLongPress
UI/Interaction
A React hook that handles both normal press and long press interactions, with progress tracking and customizable callbacks.
Demo
Try pressing the button normally, holding it for a long press, or canceling a long press by releasing early:
Press and hold the button
0
Normal Presses
0
Long Presses
0
Canceled
Installation
npm install @thibault.sh/hooks
Usage
import { useLongPress } from '@thibault.sh/hooks/useLongPress';
function LongPressButton() {
const { handlers, state } = useLongPress({
delay: 500,
onPress: () => console.log('Normal press'),
onLongPress: () => console.log('Long press completed'),
onLongPressCanceled: () => console.log('Long press canceled')
});
return (
<button {...handlers}>
{state.isLongPressed
? 'Long Press!'
: `Hold me (${Math.round(state.progress * 100)}%)`}
</button>
);
}
API
Returns
Object containing event handlers and current press state
Features
- ✓Progress Tracking
Real-time progress tracking of the long press duration with smooth animation frames
- ✓Touch & Mouse Support
Works with both touch and mouse events for broad device compatibility
- ✓Customizable Timing
Adjustable delay threshold for long press detection
- ✓Rich Event Callbacks
Comprehensive set of callbacks for different press states and events
Context Menu Example
import { useLongPress } from '@thibault.sh/hooks/useLongPress';
function ContextMenuButton() {
const [menuPosition, setMenuPosition] = useState<{ x: number; y: number } | null>(null);
const { handlers } = useLongPress({
delay: 500,
preventContext: true,
onPress: () => setMenuPosition(null),
onLongPress: (event) => {
// Position context menu at press location
const { clientX, clientY } = event instanceof TouchEvent
? event.touches[0]
: event;
setMenuPosition({ x: clientX, y: clientY });
}
});
return (
<>
<button {...handlers}>
Long press for context menu
</button>
{menuPosition && (
<div
style={{
position: 'fixed',
top: menuPosition.y,
left: menuPosition.x,
}}
>
{/* Context menu content */}
</div>
)}
</>
);
}
Delete Confirmation Example
import { useLongPress } from '@thibault.sh/hooks/useLongPress';
function DeleteButton({ onDelete }: { onDelete: () => void }) {
const { handlers, state } = useLongPress({
delay: 2000,
onLongPress: onDelete,
onLongPressCanceled: () => console.log('Delete canceled')
});
return (
<button
{...handlers}
className={`${
state.isPressed
? 'bg-red-500'
: 'bg-gray-200'
} relative overflow-hidden`}
>
{state.isLongPressed ? (
'Deleted!'
) : (
<>
Hold to Delete
{state.isPressed && (
<div
className="absolute bottom-0 left-0 h-1 bg-red-700"
style={{ width: `${state.progress * 100}%` }}
/>
)}
</>
)}
</button>
);
}