19

I am able to make a hidden div show/hide when an input field is in focus/blur using the following code:

  $('#example').focus(function() {
    $('div.example').css('display','block');
  }).blur(function() {
    $('div.example').fadeOut('medium');
  });

The problem is I want div.example to continue to be visible when the user is interacting within this div. E.g. click, or highlighting the text etc. within div.example. However div.example fades out whenever the input is not in focus and the mouse is interacting with elements within the div.

The html code for the input and div elements is as follows:

<p>
<label for="example">Text:</label>
<input id="example" name="example" type="text" maxlength="100" />
<div class="example">Some text...<br /><br />More text...</div>
</p>

How do I make it such that the div.example only disappears when the user clicks outside the input and/or div.example? I tried experimenting with focusin/focusout to check the focus on <p> but that didn't work either.

Would it matter that div.example is positioned directly below the input field #example using jQuery? The code that does that is as follows:

var fieldExample = $('#example');
$('div.example').css("position","absolute");
$('div.example').css("left", fieldExample.offset().left);
$('div.example').css("top", fieldExample.offset().top + fieldExample.outerHeight());

My apologies if this has been asked before, but the many show/hide div questions I read does not cover this. Thanks for your advice. :)

Lyon
  • 7,354
  • 10
  • 33
  • 46

4 Answers4

30

If you track the focusin event on the document since focusin bubbles then you can figure out if the new thing in focus is "outside" and if so do something about it. This will work for both clicks and tabbing.

$('#example').focus(function() {
    var div = $('div.example').show();
    $(document).bind('focusin.example click.example',function(e) {
        if ($(e.target).closest('.example, #example').length) return;
        $(document).unbind('.example');
        div.fadeOut('medium');
    });
});
$('div.example').hide();​

Updated the code to use both the focusin and click event to decide if to hide the div.example. I am using namespaced events so that I can call unbind('.example') to unbind both of them.

Example: http://jsfiddle.net/9XmVT/11/

Side Note Change your css positioning code to only call the css method once:

$('div.example').css({
    "position":"absolute",
    "left": fieldExample.offset().left,
    "top": fieldExample.offset().top + fieldExample.outerHeight()
});

Example with using the absolute positioned div: http://jsfiddle.net/9XmVT/14/

UPDATE

Ben Alman just updated his clickoutside event and converted it to handle alot of *outside events. http://benalman.com/projects/jquery-outside-events-plugin/

Would let you do something like this:

$('#example').focus(function() {
    $('div.example').show().bind('focusoutside clickoutside',function(e) {
        $(this).unbind('focusoutside clickoutside').fadeOut('medium');
    });
});
$('div.example').hide();
PetersenDidIt
  • 25,562
  • 3
  • 67
  • 72
  • hi peter, unfortunately, the div still disappears. When you click or select the text in that div.example, I want it to stay visible. Until the user specifically clicks elsewhere, should the div disappear. Appreciate your help here. Thanks :) – Lyon Mar 12 '10 at 00:57
  • @Lyon you are correct. Just updated my answer with a way that should work for you. – PetersenDidIt Mar 12 '10 at 01:45
  • Thanks Peter. I really appreciate your help on this. I've been racking my brains trying to figure out how to do this. Could it also be done such that when the user clicks elsewhere, like text on the page, or the page background, (e.g. input/div no longer in focus), that div.example will disappear too? Currently, it only disappears when I click on the next input. Thank you so much. I'm trying to adapt your code to do that to no avail :( – Lyon Mar 12 '10 at 02:38
  • @Lyon updated the answer to handle clicks and tabbing, should fix the problem of clicking on text and it not hiding – PetersenDidIt Mar 14 '10 at 02:08
  • @Lyon Ben Alman just updated his clickoutside event plugin to handle more then just clicking outside. http://benalman.com/projects/jquery-outside-events-plugin/ Something you might be interested in. – PetersenDidIt Mar 17 '10 at 11:58
  • If anyone needs multiple inputs + hidden divs I asked the question at Stack Exchange Code Review: https://codereview.stackexchange.com/questions/212253/on-form-inputs-focus-show-div-hide-div-on-blur-for-multiple-inputs-and-hidden#212254 +1 @P – Kerry7777 Jan 26 '19 at 09:07
2

http://jsfiddle.net/9XmVT/699/

dead while onclick with Iframe

TomSawyer
  • 3,711
  • 6
  • 44
  • 79
1

You could use a timer to introduce a slight delay, and stop the timer if there's a focus on the field or a click on the div:

var timer = false ;
$('#example').focus(function() {
    if (timer)
        clearTimeout(timer);
    $('div.example').css('display','block');

  }).blur(function() {

    if (timer)
        clearTimeout(timer);

    timer = setTimeout(function(){
            $('div.example').fadeOut('medium');
        },500);

  });

$('div.example').click(function(){
    if (timer)
        clearTimeout(timer);
})
Ben
  • 20,737
  • 12
  • 71
  • 115
0

A plain JavaScript way of solving this would be to use relatedTarget in combination with a wrapper. And because of how relatedTarget works, your div.example will need to be focusable for it to work with relatedTarget. But because div elements aren't focusable by default, you will need to make your div.example focusable by adding either tabindex="0" or tabindex="-1" attribute to the element. You can read the difference between the two in this MDN tabindex documentation.

Run the following code to see this in action. I have added a red border to the div.example element for better representation.

const wrapper = document.getElementById("wrapper");
const toggle = document.querySelector("#example");
const target = document.querySelector("div.example");

toggle.addEventListener("focus", () => {
  target.style.display = "";
});

wrapper.addEventListener("focusout", (event) => {
  if (wrapper.contains(event.relatedTarget)) {
    return;
  }
  target.style.display = "none";
});
<div id="wrapper">
  <label for="example">Text:</label>
  <input id="example" name="example" type="text" maxlength="100" />
  <div class="example" tabindex="0" style="border: 1px solid red;">Some text...<br />More text...</div>
</div>
arafatgazi
  • 341
  • 4
  • 5