Existing jQuery plugin? Detect if child element has focus

Hey, does anyone know of a plugin that, if a child element has focus, a parent element you specify can get focus? E.g. in this case, if the footer anchor is focused, I want the <section> to be able to get a class or something.

<section>
  <header>
    <h2>Title Here</h2>
  </header>
  <div class="content">
    <p>Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Praesent Maecenas faucibus mollis interdum. Nulla vitae elit libero, a pharetra augue. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh.</p>
  </div>
  <footer>
    <a href="#thing">Go To Page</a>
  </footer>
</section>

Hey Ryan, the basic approach is actually be quite straight forward with regular jQuery…

$('a')
  .focus(function () {
    $(this).closest('section').addClass('active')
  })
  .blur(function () {
    $(this).closest('section').removeClass('active')
  })

Although querying for the closest section all the time is rather expensive; it would be better to cache that element. You might then wrap this in a small extension like

$.fn.focusToggle = function focusToggle (selector, className) {
  return this.each(function () {
    var $this = $(this)
    var $closest = $this.closest(selector)

    $this
      .focus(function () {
        $closest.addClass(className)
      })
      .blur(function () {
        $closest.removeClass(className)
      })    
  })
}

// Usage
$('a').focusToggle('section', 'active')

PS: You might also make it more reusable by having the extension take callback functions instead of class name, like e.g.

$.fn.parentFocus = function focusToggle (selector, focusFn, blurFn) {
  return this.each(function () {
    var $this = $(this)
    var $closest = $this.closest(selector)

    $this
      .focus(function () {
        $closest.each(focusFn)
      })
      .blur(function () {
        $closest.each(blurFn || focusFn)
      })    
  })
}

// Usage
$('a').parentFocus('section', function () {
  $(this).toggleClass('active')
})
1 Like

Thanks! I put a 2nd anchor on the page and also an input, and changed the selector on the jquery call…why is the first element screwed up as you tab through it?

c odere po.de mo.fina lsite.com/keyb oard-in ner-an chor-ele ment

My page currently has your second version of the plugin, not the first, but still screwy.

$('a, input').parentFocus('section', function () {
              $(this).toggleClass('active');
            });

My page has that in.

Hm… my first guess was that immediately removing and re-adding that class would break some animation, but if all you have is a CSS top transition that can’t be the problem. With just that, I can’t reproduce the problem – see this pen.

There must be something else in play here… can you break down the bug in a smaller pen where the relevant JS and CSS is all in one place?

Nice idea to handle the keyboard navigation BTW. :-)

1 Like

Thanks!
https://codepen.io/ryanreese09/pen/ZyWGRK

That pen still shows the issue…working on narrowing down the code…No matter what, I can’t get yours to show the bug, so it must just be something with the way I’m working this…

Check out line 50…Figured it out…Uncomment it and re-run it and check how that pseudo element breaks it…

1 Like

Whoa. This is weird. I’m really curious now why this is happening… :-P

1 Like

Can you show an example of how you’d call external functions? I figured out how to call functions within the plugin call.

$('a, input').parentFocus('section', function () {
              $(this).addClass('active');
                console.log('add');
            }, function() {
                $(this).removeClass('active');
                console.log('remove');
            });

Hopefully last question. You’ve been very helpful :slight_smile: .

No worries, glad I could help! Not sure what you mean with calling external functions though… if the functions are available in the outer scope, you can call them inside the callbacks as usual – or just pass them in as callbacks themselves.

1 Like

Like this :slight_smile: . Got it. Thanks!

function addC(ele) {
                $(this).addClass("active");
                console.log('add FUNCTION');
            }
            function removeC(ele) {
                $(this).removeClass("active");
                console.log('remove FUNCTION');
            }
            $('a, input').parentFocus('section', addC, removeC);
1 Like

And a third way…

function addC(ele) {
  $(ele).addClass("active");
  console.log('add3');
}
function removeC(ele) {
  $(ele).removeClass("active");
  console.log('remove3');
}
$('a, input').parentFocus('.box', function() {
    addC($(this));
},
function() {
  removeC($(this));
});

I think I’m all set. Lovely solution. Thanks again.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.