Skip to content

Instantly share code, notes, and snippets.

@mauskin
Last active May 26, 2025 15:41
Show Gist options
  • Save mauskin/1eef265eb80282a9cf0eb84362fc6937 to your computer and use it in GitHub Desktop.
Save mauskin/1eef265eb80282a9cf0eb84362fc6937 to your computer and use it in GitHub Desktop.
Minimal cross-browser drag with no drop function
// The most bare cross-browser drag with no drop function I could do.
// Example:
//
// make_draggable(
// thing,
// () => console.log("let’s go"),
// (event) => {
// console.log(event.clientX, event.clientY);
// element.style.transform = `translate(${event.clientX}px, ${event.clientY}px)`;
// },
// () => console.log("landed")
// );
export default Object.freeze(function make_draggable(
element, // element, being dragged
on_drag_start, // callback, runs once, gets `event` and `drag_state`
on_drag, // callback, runs a lot, gets `event` and `drag_state`
on_drag_end // callback, runs once, gets `event` and `drag_state`
) {
if (element === null || element === undefined) {
console.error("Element is missing");
return undefined;
}
if (
typeof on_drag_start !== "function" ||
typeof on_drag !== "function" ||
typeof on_drag_end !== "function"
) {
console.error("All three handlers are required");
return undefined;
}
let drag_state;
function drag_start_handler(event) {
element.setPointerCapture(event.pointerId);
window.addEventListener("pointermove", drag_handler, true);
element.addEventListener("pointerup", drag_end_handler, true);
element.addEventListener("pointercancel", drag_end_handler, true);
drag_state = Object.create(null);
on_drag_start(event, drag_state);
}
function drag_handler(event) {
on_drag(event, drag_state);
}
function drag_end_handler(event) {
window.removeEventListener("pointermove", drag_handler, true);
element.removeEventListener("pointerup", drag_end_handler, true);
element.removeEventListener("pointercancel", drag_end_handler, true);
element.releasePointerCapture(event.pointerId);
on_drag_end(event, drag_state);
}
element.addEventListener("pointerdown", drag_start_handler, true);
return Object.freeze(function clean_up() {
element.removeEventListener("pointerdown", drag_start_handler, true);
window.removeEventListener("pointermove", drag_handler, true);
element.removeEventListener("pointerup", drag_end_handler, true);
element.removeEventListener("pointercancel", drag_end_handler, true);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment