Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining when focus occurs outside an element

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 href="#">Title</a>
  </li>
  <li>
    <ul>
      <li>
        <a href="#">Some link</a>
      </li>
      <li>
        <a href="#">Some link</a>
      </li>
      <li>
        <a href="#">Some link</a>
      </li>
      <li>
        <a 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.

like image 634
AGE Avatar asked Jan 07 '16 00:01

AGE


People also ask

How do you know if an element is clicked outside?

You can listen for a click event on document and then make sure #menucontainer is not an ancestor or the target of the clicked element by using . closest() . If it is not, then the clicked element is outside of the #menucontainer and you can safely hide it.

How do you trigger an event when clicking outside the Element?

Answer: Use the event. target Property You can use the event. target property to detect a click outside of an element such as dropdown menu.

How do you know which element is focused?

To check whether a specific element has focus, it's simpler: var input_focused = document. activeElement === input && document. hasFocus();


2 Answers

I'm not sure I'm following the question 100% but I think I got you.

You can use event.target with closest using the focusin event.

$(document).on('focusin', function (event) {
  var $target = $(event.target);
  if (!$target.closest('.bar').length) {
    console.log('You focused outside of .bar!');
  }
});

Here's a fiddle: https://jsfiddle.net/crswll/qk14r7c7/2/

like image 140
Bill Criswell Avatar answered Oct 05 '22 02:10

Bill Criswell


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/

like image 25
nrabinowitz Avatar answered Oct 05 '22 00:10

nrabinowitz