use-onclickoutside
use-onclickoutside copied to clipboard
[Question] Why does it use "mousedown" and not "click"?
I'm just wondered why is that so? Was it done intentionally? 🤔
I've chosen this based on other popular solutions. Don't have a specific answer for this, if this brings you any trouble I might consider making this configurable
If I'm not mistaken, I had an issue similar to this one:
https://codesandbox.io/s/dreamy-lake-knr2w
onMouseDown is triggered first, it closes the tooltip, but then onClick opens it again. Not a really big case, but I was interested in, so I'm here. :)
const Tooltip = () => {
const [show, toggle] = useState(false);
const ref = useRef(null);
useOnClickOutside(ref, () => toggle(false));
return (
<button onClick={() => toggle(!show)}>
toggle
{show && (
<div ref={ref} className="tooltip">
test
</div>
)}
</button>
);
};
I'm facing the same problem here :(
Couldnt u move tooltip outside of the button element in this example?
I solved it creating a ref to toggle button and checking it in event target
const menuRef = useRef(null)
const menuTogglerRef = useRef(null)
useOnClickOutside(menuRef, e => {
if (!menuTogglerRef.current.contains(e.target)) {
setMenuOpened(false)
}
})
It worked, but not so fancy as I wanted xD
First of all, a default behaviour for desktops since years is to perform actions after releasing mouse button and not immediately after pressing it. You can check it yourself by clicking at any link on this site. Secondly, in some cases using 'mousedown' instead of 'mouseup' or 'click' causes flickering, because there is always a small delay between pressing & releasing a button. The event should be configurable, otherwise reusability of this hook is very low.
I could accept a PR to make this particular thing configurable.
@ElForastero, @Andarist, I suppose mousepress and touchpress events are used to process some cases better. The most striking example is the starting of a container scroll. It may be useful if your popup have got no dynamic position recalculation and should be closed before a container was scrolled.
@Norserium it's not sufficient to address issues with scroll, as scroll is not only launched by mousepress and touchpress, but also by keyboard keys, mouse scrollwheel actions... So the scroll justification is not enough for this technical choice. The reason I believe is rather that most UX actions use the click event, and some do stopPropagation, preventing it from bubbling all the way to document, and to this handler... I thought for a while about it and I don't see any simple solution for all use cases...
I finally found a simple solution for my use case, which I believe is pretty common: How to prevent an outside click from registering ? For example you use use-onclickoutside to detect clicks outside of a context menu in order to close it, but you don't want the clicks outside to register otherwise (ie you don't want a click outside to have an effect on a button, you just want it to close the menu). The solution is to stop propagation of the next 'click' event on the document, in the capture phase:
const disableNextClick = () => {
const listener = (evt)=> {
evt.stopPropagation();
document.removeEventListener('click', listener, true);
};
document.addEventListener('click', listener, true);
};
useOnClickOutside(menuRef, () => {
setIsMenuOpen(false);
disableNextClick();
});