Enhancing Web Accessibility: Locking the TAB Button within Modals and Menus
Tags: tutorial, a11y, javascript, webdev
Published: 2023-07-26 20:36:10

This is a very important accessibility feature to use on your site.

You might not know this, but many users use keyboard navigation. Some of them have motor disabilities, some may use a keyboard for navigation because of preference or efficiency.

> **The point is your site must be accessible with the keyboard alone.**

First of all, I hope you already know you should highlight all focusable elements on your site (like links and buttons) when they are on focus. At least when they are focused by the keyboard TAB button.

There’s a very useful pseudo-class in CSS called `:focus-visible`. In simple words, it applies to an element when it is focused by the TAB button. You can read more about it on [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible).

But let’s get back to the case.

So you have a site with a fullscreen menu or some other section that opens full screen size. Something like this:

![](https://cdn-images-1.medium.com/max/1024/0*I1BfTpYeXbjqsg6T)
_A site with a fullscreen menu_

Then a user reaches to that section with a keyboard navigation (TAB button) and opens it by hitting the ENTER button:

![](https://cdn-images-1.medium.com/max/600/0*T_p3TjQPRMx6LtAW)

What should happen after the user reaches the last link in the section?

Unfortunately, it’s a very common case when the user keeps navigating to the next links **_outside_** that full screen section.

As a result, users get totally lost on your site. They don’t see focused links anymore (because they are hidden below the fullscreen section) and yet they keep navigating on the page.

A good example of how it **_should_** work demonstrates [the Fancybox JS plugin](https://fancyapps.com/). Go to their [examples section](https://fancyapps.com/fancybox/#examples), click on any picture and then navigate through the opened modal only with your keyboard. You won’t get outside that modal until you close it.

![](https://cdn-images-1.medium.com/max/600/0*X2gYEq4E70hukRMz)
_Lock TAB inside Fancybox_

So what’s the solution?

It’s quite simple — when the fullscreen section was opened, the user should be able to navigate only within that section by a keyboard.

This is what we expect to get:

![](https://cdn-images-1.medium.com/max/600/0*0ARLE4UAs2jujcgn)

To achieve that, let’s write some JavaScript code to lock the TAB within the fullscreen menu:

```
// Get the menu button element
const menuBtn = document.querySelector(".menu-btn");

// Get the close menu button element
const closeMenuBtn = document.querySelector(".close-btn");

// Get the fullscreen menu element
const fullscreenMenu = document.getElementById("fullscreenMenu");

// Function to toggle the menu
function toggleMenu() {
  fullscreenMenu.classList.toggle("active");
  menuBtn.classList.toggle("active");
}

// Add event listener to the menu button for the 'click' event
menuBtn.addEventListener("click", toggleMenu);
closeMenuBtn.addEventListener("click", toggleMenu);

// Add event listener to the 'keydown' event on the document
document.addEventListener("keydown", function (e) {
  const target = e.target;
  const shiftPressed = e.shiftKey;

  // If TAB key pressed
  if (e.keyCode === 9) {
    // If inside a fullscreen menu (determined by attribute role="dialog")
    if (target.closest('[role="dialog"]')) {
      // Find the first or the last input element in the dialog parent (depending on whether Shift was pressed).
      // Get the focusable elements (links and buttons)
      let focusElements = target
        .closest('[role="dialog"]')
        .querySelectorAll("a[href], button");
      let borderElem = shiftPressed
        ? focusElements[0]
        : focusElements[focusElements.length - 1];

      if (borderElem) {
        // If the current target element is the first or last focusable element in the dialog, prevent the default behaviour.
        if (target === borderElem) {
          e.preventDefault();

          // move focus to the first element when the last one is reached and vice versa
          borderElem === focusElements[0]
            ? focusElements[focusElements.length - 1].focus()
            : focusElements[0].focus();
        }
      }
    }
  }
});
```

Here’s the demo how it should be:

{% codepen https://codepen.io/bogdanfromkyiv/pen/gOQjmPg %}

Thus, we can prevent elements from focusing outside full screen menus or modal popups while they are opened.

---

Check my other articles about web optimisation:

- [RAM Technique in CSS](https://dev.to/bogdanfromkyiv/ram-technique-in-css-1lk7)
- [Lazy Load for videos with plain JS](https://medium.com/@bogdanfromkyiv/lazy-load-for-videos-with-plain-js-ef0671dda64)
- [Dynamic font-size using only CSS3](https://medium.com/@bogdanfromkyiv/dynamic-font-size-using-only-css3-757ea901d0fe)

---

If you find this article helpful — don’t hesitate to like, subscribe and leave your thoughts in the comments 😊

---

**[Read more posts on my Medium blog](https://medium.com/@bogdanfromkyiv)**

---

Thanks for reading!  
Stay safe and peace be with you!