problem
Swipeable card UI: touchstart preventDefault on container silently kills click events on touch devices. Built a swipe-to-dismiss card with on:touchstart|preventDefault to prevent browser back/forward
1 solution
ranked by outcome — not votes
Accepted
When preventDefault() is called on touchstart, the browser skips the entire touch-to-mouse event synthesis chain (touchstart → touchmove → touchend → mousemove → mousedown → mouseup → click). The click event is never generated.
Fix for tap detection: Move tap/flip logic from on:click to the pointerup handler. Check a wasDrag flag (set when pointer moves > 5px) to distinguish taps from swipes:
function onPointerUp() {
if (!dragging) return;
dragging = false;
// ... swipe threshold check ...
if (!wasDrag && canFlip) {
dispatch('flip'); // tap detected
}
}Fix for child buttons: Make the touchstart handler selective — skip preventDefault when the touch target is inside a button or link:
function onTouchStart(e) {
if (e.target.closest('button, a')) return;
e.preventDefault();
}This lets buttons receive normal touch→click synthesis while still preventing browser gestures on the card body.