use-onclickoutside icon indicating copy to clipboard operation
use-onclickoutside copied to clipboard

[Question] Why does it use "mousedown" and not "click"?

Open ElForastero opened this issue 6 years ago • 10 comments

I'm just wondered why is that so? Was it done intentionally? 🤔

ElForastero avatar Apr 14 '19 05:04 ElForastero

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

Andarist avatar May 15 '19 12:05 Andarist

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>
  );
};

ElForastero avatar May 15 '19 17:05 ElForastero

I'm facing the same problem here :(

renatorib avatar Jul 04 '19 20:07 renatorib

Couldnt u move tooltip outside of the button element in this example?

Andarist avatar Jul 05 '19 05:07 Andarist

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

renatorib avatar Jul 09 '19 19:07 renatorib

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.

mrosinski avatar Aug 17 '19 10:08 mrosinski

I could accept a PR to make this particular thing configurable.

Andarist avatar Aug 18 '19 07:08 Andarist

@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 avatar Jun 08 '20 14:06 Norserium

@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...

barroudjo avatar Oct 27 '20 11:10 barroudjo

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();
  });

barroudjo avatar Oct 29 '20 09:10 barroudjo