Cannot open another submenu below an open submenu in vertical mode

Created on 4 December 2024, 7 months ago

Problem/Motivation

When using the menu in vertical mode, trying to open a second submenu below an already open submenu fails. I think this is due to a timing conflict between the blur and click events.

Steps to reproduce

  1. Create a menu with at least two menu items with submenus.
  2. Add a Disclosure Menu block and change it to a vertical menu.
  3. Open a submenu by clicking its toggle button.
  4. Attempt to open a second submenu below the first one by clicking its toggle button.
  5. Observe that the second menu does not open.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Active

Version

2.1

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States hbrokmeier Wisconsin

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @hbrokmeier
  • πŸ‡ΊπŸ‡ΈUnited States jayhuskins

    Do you have hover JS enabled? If so, which setting do you have selected for "Resolve disclosure button hover and click"?

  • πŸ‡ΊπŸ‡ΈUnited States hbrokmeier Wisconsin

    hover JS is disabled in this scenario

  • I have created the patch please review it

  • πŸ‡ΊπŸ‡ΈUnited States sonfd Portland, ME

    Hiding irrelevant patch - it looks like it was added to the wrong issue.

  • πŸ‡ΊπŸ‡ΈUnited States sonfd Portland, ME

    Taking a look at this - it looks like our issue has to do with the order of the blur / click events.

    If I google, "javascript blur click event order", I get an AI explanation with:

    The order of events when a user interacts with an element that has both blur and click event handlers is as follows:

    1. mousedown: This event fires when the mouse button is pressed down on the element.
    2. blur: If the element loses focus (e.g., by clicking outside of it), the blur event fires.
    3. mouseup: This event fires when the mouse button is released.
    4. click: This event fires after the mouseup event if the mouse button was both pressed and released over the same element.

    I'm not easily finding the source of this info, but in our case, if we open one submenu, for example the first submenu in our vertical menu, and then click the second submenu's toggle, only the first submenu is closed, the second submenu is not opened. I believe this is because of this event ordering and because our mouse is no longer hovering over the originally clicked toggle by the time the click event tries to fire.

    I can confirm that the click event never fires with some console.logs in toggleMenu, hideMenu, and showMenu functions.

    However, if I change the click event to trigger on mousedown, all works as expected. This further supports the theory that the issue is that the mouse is not hovering on the same item that was clicked when the click event attempts to fire.

    Also, if I comment the toggle's blur event, my second submenu opens, but of course the first does not close.

    I think we can change the toggle's blur event to achieve a similar effect, but without this issue. Perhaps by just substituting with focusout, but I will look into this more tomorrow.

  • πŸ‡ΊπŸ‡ΈUnited States sonfd Portland, ME

    Swapping to focusout did not resolve anything, the same issue persists.

  • πŸ‡ΊπŸ‡ΈUnited States sonfd Portland, ME

    I found an approach that seems to work as expected.

    toggle.addEventListener('blur', (event) => {
      if (!menu.contains(event.relatedTarget)) hideMenu(toggle, menu);
        if (!menu.contains(event.relatedTarget)) {
          setTimeout(() => hideMenu(toggle, menu), 0);
        }
     });
    

    The important change is that instead of calling hideMenu(toggle, menu) immediately from the blur event handler, instead we call setTimeout(() => hideMenu(toggle, menu), 0); so hiding the menu happens "during the next event cycle."

    In most cases, this difference is not relevant, but it is necessary when using a vertical menu style. Without this delay, if a user has toggled open a submenu and then clicks the toggle button of a later submenu, e.g. the next one, the open submenu will close, but the second submenu will not open. This is because the blur event (which closes the first submenu) triggers before the click event (which opens the second submenu) and the click event will not fire if the user's cursor is no longer over the element they originally clicked (in our example scenario, the user's cursor is no longer over the original element because the closing of the first submenu has shifted our element higher on the screen). By using setTimeout with a delay of 0, we can trigger hiding the menu to happen "during the next event cycle" (see https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#delay) which occurs after the click event is resolved.

  • πŸ‡ΊπŸ‡ΈUnited States sonfd Portland, ME
  • Pipeline finished with Skipped
    6 months ago
    #387744
  • πŸ‡ΊπŸ‡ΈUnited States jayhuskins
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024