Ad

Determining When Focus Occurs Outside An Element

- 1 answer

I am trying to see if the following is possible:

  • Determining if focus occurs outside an element without the use of document level global selectors such as $(document), $(body), $(window) and the like due to performance reasons.
  • If it is not possible to achieve without global selectors, explain yourself with a provable reason. It is important that I understand why this is not doable with today's latest techniques.
  • Bonus Round: Determining the most efficient (computation time wise) selector(s)/event handler(s)/plugin(s) for the task.

My implementation consists of a very simple HTML navigation bar as seen in the snippet below. I do native keyboard navigation between each <a> tag. The first list element is the title, containing an anchor that is visible, the second element

<ul class="test">
  <li>
    <a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="#">Title</a>
  </li>
  <li>
    <ul>
      <li>
        <a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="#">Some link</a>
      </li>
      <li>
        <a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="#">Some link</a>
      </li>
      <li>
        <a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="#">Some link</a>
      </li>
      <li>
        <a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="#">Some link</a>
      </li>
    </ul>
  </li>
</ul>

The goal of this navigation bar is simple:

  1. Native keyboard tab or shift+tab to go from anchor to anchor.
  2. Show the drop down menu when focusing on the inner anchor elements.
  3. Hide the drop down menu when not focusing on any inner anchor elements.

I have 1 and 2 down, but 3 is tricky because of the requirements listed above. I know this can be very easily be done using a global selector, but this challenge is about figuring out and understanding if it can be done otherwise.

$(document).ready(function() {
    dropdownMenu = $(".test > ul");
    dropdownMenu.hide();

    $(".test").focusin(function() {
        if (dropdownMenu.is(":hidden")) {
          dropdownMenu.show();
        }
    });
    // Some selector for some event here to handle the focus/clicks outside the $(".test") element
});

Important: I consider event.stopPropagation();, as explained in CSS Tricks - The Dangers of Stopping Event Propagation to be a dangerous technique for the scope of this question, however if using said technique results in the most efficient approach then I will welcome it.

Ad

Answer

One option here, without global selectors, is to delay the close action briefly:

  var isVisible = false;

  $(".test").focusin(function() {
    if (dropdownMenu.is(":hidden")) {
      dropdownMenu.show();
    }
    isFocused = true;
  });

  $(".test").focusout(function() {
    isFocused = false;
    setTimeout(function() {
      if (!isFocused && dropdownMenu.is(":visible")) {
        dropdownMenu.hide();
      }
    }, 100);
  });

This is a little fiddly, but protects you from errant closes while tabbing. See https://jsfiddle.net/d5fa5o8q/4/

Ad
source: stackoverflow.com
Ad