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 ↗