v148 · Web APIs · Drag & Drop

Pointer event suppression on drag start

Chrome 148 aligns with the HTML spec: when a drag operation starts, the browser sends a pointercancel event to the drag source to signal that the pointer event stream has ended. This ensures that pointer event listeners don't continue to fire unexpectedly during a drag.

concepts

  1. Drag Events Demo

    Drag the element and watch the event log. In Chrome 148+, a pointercancel event fires as soon as the drag starts, suppressing further pointermove events on the drag source. Before Chrome 148, pointer move events continued firing during the drag.

  2. Event Sequence Viewer

    Shows the full expected event sequence for a drag gesture: pointerdownpointermove → drag start → pointercancel → drag events → pointerup. Compare Chrome 148 vs prior behaviour.

  3. State Machine Visualiser

    Canvas-drawn state machine showing Idle → Pointer → Drag → Done transitions in real time. Drag the target element and watch the pointercancel node light up — the Chrome 148 spec fix made visible.

  4. Multi-touch Drag Demo

    A 3×3 grid of draggable tiles with a live event log timestamped by pointer ID. Start dragging one tile and watch pointercancel suppress that pointer's stream. A "Simulate second touch" button starts a second independent pointer — demonstrating that only the dragging pointer is suppressed, others remain active. State diagram and per-pointer-ID badges show suppressed vs active status at a glance.

  5. Cleanup Pattern Demo

    Side-by-side comparison of a broken pointer-tracking pattern (no pointercancel handler — move events leak into the drag) vs the correct pattern (cleans up via pointercancel the moment Chrome 148 fires it at drag start). A progress bar and event log make the difference visible as you drag each card.

why it shipped

The HTML specification says that when a drag starts, the user agent should fire pointercancel on the drag source to indicate the pointer event stream has been "captured" by the drag. Before Chrome 148, Chrome didn't do this — pointer event listeners could fire unexpectedly during a drag, causing issues for custom drag-and-drop implementations that tried to handle both the Drag and Drop API and Pointer Events simultaneously.

the event sequence

// Chrome 148+ event sequence for a drag gesture:
// 1. pointerdown    → drag starts here (mousedown equivalent)
// 2. pointermove    → brief move before drag threshold met
// 3. pointercancel  → ← NEW in Chrome 148: drag took over the pointer stream
// 4. dragstart      → HTML Drag and Drop API takes over
// 5. drag           → fires while dragging (pointer events suppressed)
// 6. dragenter / dragover / dragleave on targets
// 7. drop           → on valid drop target
// 8. dragend        → drag sequence complete

// Before Chrome 148:
// pointerdown → pointermove → pointermove → ... (kept firing during drag!)
// → dragstart (but pointer events weren't cancelled)

el.addEventListener('pointercancel', e => {
  // Chrome 148+: fires when drag starts
  // Safe to clean up any pointer-tracking state here
  cleanup();
});

references

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗