v148 · Web APIs · Drag & Drop
Cleanup Pattern Demo
See the difference between a broken cleanup pattern (that keeps tracking pointer position during a drag) and the correct pattern using pointercancel to stop tracking when Chrome 148 fires it on drag start. Drag each card and watch the progress bar and event log.
Drag either card below. The Broken Pattern progress bar will keep growing during the drag (pointer move events leak into the drag). The Correct Pattern bar stops immediately when
pointercancel fires — as it should in Chrome 148+.
Broken pattern — no pointercancel cleanup
Idle
Drag me
pointermove count during drag:
0 moves
Correct pattern — cleanup via pointercancel
Idle
Drag me
pointermove count during drag:
0 moves
the two patterns
// ❌ BROKEN — no pointercancel handler
el.addEventListener('pointerdown', e => {
tracking = true; // start tracking
progress = 0;
});
el.addEventListener('pointermove', e => {
if (!tracking) return;
// ← runs during drag too! should not.
progress += e.movementX;
updateUI(progress);
});
el.addEventListener('pointerup', () => { tracking = false; });
// No pointercancel handler → tracking keeps firing after dragstart
// ✓ CORRECT — cleanup via pointercancel (fires on dragstart in Chrome 148)
el.addEventListener('pointerdown', e => {
tracking = true;
progress = 0;
});
el.addEventListener('pointermove', e => {
if (!tracking) return; // guard still there
progress += e.movementX;
updateUI(progress);
});
el.addEventListener('pointercancel', () => {
tracking = false; // ← Chrome 148 fires this at dragstart
cleanup(); // safe to release resources
});
el.addEventListener('pointerup', () => { tracking = false; });
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗