How to focus on a specific element when a button is pressed

2.3k views Asked by At

I have an off-canvas-menu (#mobile-menu) that opens when a button/trigger (.mobile-menu-toggle) is clicked or pressed etc.

The menu opens fine on keyboard press, but it does not focus within the menu, instead the focus is on the next element in the document flow - the menu actually comes before the "trigger" in the document.

So I'm looking for a way to set the focus within the off-canvas-menu when it opens.

I have tried many variations of this, but nothing happens, the focus is still going to the next element instead of what I've specified:

$(document).on("keyup",".mobile-menu-toggle",function(e) {
    if (e.which == 13) {
        $("#mobile-menu ul").focus();
    }
});

And here's a simplified version of the html:

 <nav id="mobile-menu" aria-label="Main Mobile Navigation">
    <div class="content">
            
        <a href="#" aria-label="Mobile Homepage Link">... LOGO IMG ...</a>

        <span class="heading">Navigation</span>

        <ul class="page-navigation">
            ... NAV LINKS ...
        </ul>

    </div>
 </nav>
                    
<div id="mobile-nav-trigger">
    <button class="mobile-menu-toggle" aria-label="Open Menu"></button>
</div>

I've also found if I try to add tabindex anywhere within the mobile-menu, the trigger no longer opens it on keypress.

How can I make it so that when the trigger opens the menu, the focus is inside of the #mobile-menu element?

2

There are 2 answers

2
ByteMyPixel On BEST ANSWER

After trying the solution found here: stackoverflow.com/a/15338848/1783695, that gave me some ideas... This solution worked, but it was also putting the focus on with a mouse click, where I just wanted the focus on keyboard press.

So I ended up with this, and it's working exactly how I needed:

var input = document.getElementById("mobile-menu-toggle");
input.addEventListener("keyup", function(event) {
    if (event.keyCode === 13) {
        event.preventDefault();
        $('.heading.focusable')[0].focus();
    }
});

Note: I added the class "focusable" and tabindex to the "Navigation" heading (we have more than one "heading" element) so it can focus there:

<span class="heading focusable" tabindex="0">Navigation</span>

enter image description here

0
Scott Heath On

One option is to turn off focus indicators for mouse users and turn them on for keyboard (TAB) users.

You will need to add the following class to your stylesheet:

body.focusIndicatorOff :focus { outline: 0; }

This style hides focus indicators for any element in the body that has focus. Next, add the following:

  1. Add the .focusIndicatorOff class style shown above to your stylesheet.
  2. Add the focusIndicatorOff class to the body element. When your page loads, the focus indicator will be hidden for all elements.
  3. Add a keypress listener to the body that listens for a TAB press.
  4. Add a mouse click listener to the body that listens for a mouse click.
  5. When a TAB press is detected, remove the focusIndicatorOff class from the body. This will make the focus indicator visible.
  6. When a mouse click is detected, add the focusIndicatorOff class to the body. This will hide the focus indicator.

With this implementation in place, update your menu button click event to simply force focus to the "Navigation" menu header. You won't have to worry about listening to a keypress on that button, just moving focus. The code I described above will detect if the user is using a mouse or a keyboard and either hide or show the focus indicator to suit their needs.

One last item: I recommend you use tabindex="-1" on the "Navigation" header. Using "-1" lets you force focus to the element but does not add it to the natural tab order.