javascriptaccessibility

Trap Focus Inside the Modal - Accessibility


I am trying to do when the modal opens, focus should move to the first focusable element inside the modal (like the close button. Also while the modal is open, users should only be able to navigate between elements inside the modal using the Tab key.

I have tried below code. But it traps in modal but after some tabs it go to the browser's address bar.

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <style>
      .modal {
         display: none;
         position: fixed;
         left: 50%;
         top: 50%;
         transform: translate(-50%, -50%);
         width: 250px;
         height: auto;
         z-index: 999;
         background-color: aliceblue;
      }
   </style>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
   <button class="openModal">Open Modal</button>
   <div class="modal">
      <button class="closeModal">Close Modal</button>
      <h4>Text here</h4>
      <a href="/main-page">Link to Main page</a>
   </div>

   <a href="/home">Home</a>
   <a href="/about">About</a>

   <script>
      $(document).on('click', '.openModal', function (e) {
         $('.modal').fadeIn();
         $('button').attr('tabindex', '-1');
         $('a').attr('tabindex', '-1');
         $('.modal button').removeAttr('tabindex',);
         $('.modal a').removeAttr('tabindex',);
      });

      $(document).on('click', '.closeModal', function (e) {
         $('.modal').fadeOut();
         $('button').removeAttr('tabindex',);
         $('a').removeAttr('tabindex',);
      });
   </script>
</body>
</html>

Solution

  • When content is hidden by default, then appears as a popup or dialog based on user behavior, there are specific techniques that are required in order to ensure the interface is accessible.

    This is a good example that I can provide you.

    Here I have created keydown events which are used to handle the tab events like I mentioned in above comment.

    $(document).on("click", ".openModal", function (e) {
      $(".modal").fadeIn();
      $(".modal .closeModal").focus();
    });
    
    $(document).on("click", ".closeModal", function (e) {
      $(".modal").fadeOut();
    });
    
    $(".modal *:last")
      .unbind()
      .bind("keydown", function (e) {
        var keyCode = e.keyCode || e.which;
        if (event.shiftKey == false && keyCode == 9) {
          setTimeout(() => {
            $(".modal .closeModal").attr("tabindex", "0");
            $(".modal .closeModal").focus();
          }, 1);
        }
      });
    
    $(".closeModal")
      .unbind()
      .bind("keydown", function (e) {
        var keyCode = e.keyCode || e.which;
        if (event.shiftKey == true && keyCode == 9) {
          setTimeout(() => {
            $(".modal a").attr("tabindex", "0");
            $(".modal a").focus();
          }, 1);
        }
      });
    .modal {
       display: none;
       position: fixed;
       left: 50%;
       top: 50%;
       transform: translate(-50%, -50%);
       width: 250px;
       height: auto;
       z-index: 999;
       background-color: aliceblue;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <button class="openModal">Open Modal</button>
    <div class="modal">
       <button class="closeModal">Close Modal</button>
       <h4>Text here</h4>
       <a href="/main-page">Link to Main page</a>
    </div>
    
    <a href="/home">Home</a>
    <a href="/about">About</a>