So I am trying to use an event listener that will trigger the handle only if any button of any type was clicked, regardless of context for the moment.
export const useClickButtonOutside = (ref, handler) => {
React.useEffect(
() => {
const listener = event => {
// Do nothing if event is not a button
if (!(event.target instanceof HTMLButtonElement)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener, { passive: false });
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
},
[ref, handler]
);
};
Main issue that is hard to achieve this is:
To achieve this, you have to take a look at the event path, which will contain all the elements where the event was fired. You need to check if this chain contains a button element, if it does, then handle the event.
export const useClickButtonOutside = (ref, handler) => {
React.useEffect(() => {
const listener = (event) => {
// Do nothing if path contains a button
let isButton = false;
event.path.forEach((element) => {
if (element.tagName === "BUTTON") {
isButton = true;
return;
}
});
if (!isButton) {
return;
}
handler(event);
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener, { passive: false });
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
};
}, [ref, handler]);
};
Can you explain more about the second point?
About the first one, when you click on a button, which has an element inside, you may receive the inside element instead of a button.
For example:
document.querySelector('button').addEventListener('click', e => {
console.log(e.target);
});
<button>
<span>Test</span>
</button>
That's because you actually had clicked on the span instead of the button, the button receive the event because of the propagation of the event.
To get the element you can do this:
document.querySelector('button').addEventListener('click', e => {
console.log(e.target.closest('button'));
});
<button>
<span>Test</span>
</button>