I have a simple web page with a button
and a div
. The button
has a click
event listener that logs to the console when clicked. The div
has a pointerdown
event listener that calls setPointerCapture
to capture pointer events.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=devicexx-width, initial-scale=1.0" />
<title>play</title>
</head>
<body>
<button id="btn">Test</button>
<div id="div" style="margin-top: 20px; height: 50px; width: 50px; background: red"></div>
<script>
const btn = document.getElementById("btn");
btn.addEventListener("click", () => console.log("btn clicked"));
const div = document.getElementById("div");
div.addEventListener("pointerdown", (e) => {
e.target.setPointerCapture(e.pointerId);
});
</script>
</body>
</html>
On Firefox, when I press mouse on the div
, drag it onto the button
and release it over the button
, the button
‘s click
event fires. This issue doesn’t happen on Edge, Safari and Chrome.
I wonder why it happens? How can I prevent the click
event fires?
I tried to manually remove that pointer capture when pointer up like this:
div.addEventListener("pointerup", (e) => {
e.target.releasePointerCapture(e.pointerId);
});
It doesn’t help.
PS: If you want to know why I want to prevent it, it’s because it’s related to this issue: https://github.com/radix-ui/primitives/issues/2777.
2
Answers
Thanks for Nanigashi. I've found that this is indeed a Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1556240. It has been discussed in: https://github.com/w3c/pointerevents/issues/356
I'd like to propose another work-round: You can use
pointer-events
properties to temporarily disable pointer events of a component. Be cautious though. It might cause unexpected side effect.This erroneous behavior is a currently known bug.
A click event is a mouse/pointer down & mouse/pointer up on the same element.
Let’s change your code a bit.
The code above allows trying various things. For example
Down & hold on the div, then drag & up to the right (body) correctly directs the target of the up event at the div, as it should with the pointer events captured there. Because the down event on the div bubbled up to the body, there’s a click on the body, but the click should be on the div.
The click should be:
Down & hold on the body, then drag & up on the div correctly reports the target of the up event as the div, because that’s where the up event took place. The up event bubbles to the body, so there’s a click event on the body.
Similarly down & hold on the body, then drag & up to the button correctly reports the target of the up event as the button. Again the up event bubbles, so there’s a click on the body.
However, down & hold on the div, then drag & up to the button correctly reports the up event on the div like it should, but also Firefox appears to be confused that the down and (captured) up events took place on the same element (the div), but the pointer is over the button. There should be no click event on the button.
As in #1, the click should be:
Here’s a work-around, if you’re desperate, to find the common ancestor of the pointerdown and pointerup events. (It won’t work with keyboard navigation, only pointers.) It would be better if Mozilla fixed the bug so clicks worked with
setPointerCapture
.