2

I'm creating a Dropdown menu using React.
But I've no idea how to implement handleClose().

enter image description here

I want:

  1. Clicking the body / anything outside the <Dropdown> => handleClose()
  2. Clicking any <ActionMenu> => handleClose()
  3. Clicking any children inside the <ActionMenu> => handleClose() if preventDefault() was not called
  4. Clicking any <ActionMenu enabled={false}> => do nothing
  5. Clicking any children inside the <ActionMenu enabled={false}> => do nothing
  6. Clicking any disabled children inside the <ActionMenu> => do nothing
  7. Clicking any <NonActionMenu> => do nothing
  8. Clicking any children inside the <NonActionMenu> => do nothing
  9. <Dropdown> lost focus (onBlur=) because an element outside dropdown got focus => handleClose()
  10. <Dropdown> lost focus (onBlur=) because an element inside dropdown got focus => do nothing

Implementing <Dropdown onBlur={() => handleClose()} ...> works for point 9 but failed for point 10.

Can you suggest your idea?

I've no sandbox because the project is quite complex.
But you can fork & modify here: my project

9
  • The handleClose() should just render the drop-down list. Nothing more. Any logic to Call the function should be done outside that. For point 10, an onFocus attribute calling the handleClose should be passed to each drop-down item. Commented Sep 19, 2021 at 15:34
  • Inside the handleClose() is calling props.?onClose(), so the user can decide to update/refuse the state: onClose={() => setShow(false)}. I'm stuggling where to spread the event for triggering handleClose() Commented Sep 19, 2021 at 15:41
  • onFocus should not causing handleClose(). Imagine a user click on an item and suddenly cancel the click (by dragging out -or- holding left click followed by right click -or- by tab key). The item got focus but not clicked. Commented Sep 19, 2021 at 15:50
  • 1
    My bad, I didn't mean onFocus. I meant onClick or when the Enter key is pressed. So when an item is clicked. It is chosen first of all and then sets the show to false which is what the handleClose function does Commented Sep 19, 2021 at 15:57
  • ok, it works, thanks. I forgot to implement enter key. Commented Sep 19, 2021 at 18:51

1 Answer 1

1

For the click, you can add an event listener to the window object to take care of any click outside the dropdown wrapper. You can also modify this for the enter key:

   window.addEventListener('click', function(e) {
        const dropDownWrapper = document.querySelector('#id of dropdown wrapper');
        const path = e.path || (e.composedPath && e.composedPath());
        if (!path.some(x => !(x instanceof SVGElement) && x.id && x.id === '#id of dropdown wrapper')) {
          dropDownWrapper.querySelector('.class of dropdownlist') ?
            x.querySelector('.class of dropdownlist').style.display = 'none' : null
          } else{
            dropDownWrapper.querySelector('.class of dropdownlist') ?
            x.querySelector('.class of dropdownlist').style.display = 'block' : null
          }
   }, true);
Sign up to request clarification or add additional context in comments.

8 Comments

hmm interesting. so it basically filter out any element === dropdownWrapper || childOrDescendantOf(element, dropdownWrapper), right?
yes, exactly. Also takes care of the element being an svg. They tend to throw an error onClick if not taken care of
I prefer focus instead of click, but focus is not bubbling in vanilla dom, only in React's synthetic event. How about handling tab key?
I'm not sure about this. But I think you should be able to replace the click with focus
unfortunately focus is not bubbling from child to parent to window. Attaching addEventListener to every element is impractical & poor performance. Maybe handling tab key + click is better.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.