Search code examples
javascripthtmlmodal-dialogwai-aria

Focus trap on <dialog> not absolute, focus escapes to browser UI elements


I am trying to get my head around the <dialog> html element and the example laid out by MDN here.

When I run the code from it...

var updateButton = document.getElementById('updateDetails');
var favDialog = document.getElementById('favDialog');
var outputBox = document.querySelector('output');
var selectEl = document.querySelector('select');
var confirmBtn = document.getElementById('confirmBtn');

// "Update details" button opens the <dialog> modally
updateButton.addEventListener('click', function onOpen() {
  if (typeof favDialog.showModal === "function") {
    favDialog.showModal();
  } else {
    alert("The <dialog> API is not supported by this browser");
  }
});
// "Favorite animal" input sets the value of the submit button
selectEl.addEventListener('change', function onSelect(e) {
  confirmBtn.value = selectEl.value;
});
// "Confirm" button of form triggers "close" on dialog because of [method="dialog"]
favDialog.addEventListener('close', function onClose() {
  outputBox.value = favDialog.returnValue + " button clicked - " + (new Date()).toString();
});
<!-- Simple pop-up dialog box containing a form -->
<dialog id="favDialog">
  <form method="dialog">
    <p><label>Favorite animal:
      <select>
        <option></option>
        <option>Brine shrimp</option>
        <option>Red panda</option>
        <option>Spider monkey</option>
      </select>
    </label></p>
    <menu>
      <button value="cancel">Cancel</button>
      <button id="confirmBtn" value="default">Confirm</button>
    </menu>
  </form>
</dialog>

<menu>
  <button id="updateDetails">Update details</button>
</menu>

<output aria-live="polite"></output>

... I find that when the dialog opens the focus does not completely "trap" like the ARIA modal example describes. They say when user presses the tab key:

When focus is on the last focusable element in the dialog, moves focus to the first focusable element in the dialog.

However the MDN example of the dialog element allows the user to "tab out" of the modal and enter the browser frame. In my case, using chrome, after the confirm button pressing tab will focus the "View site information" button then the address bar outside of the document area.

What's going on here. Is MDN's example incomplete? Would a web developer need to write additional JS code to truly focus trap in order to use the <dialog> element in production? Or is it "acceptable" from an accessibility perspective to allow a modal to partially trap the focus as in the example, where the keypress on tab can temporarily escape to browser UI elements.


Solution

  • I find that when the dialog opens the focus does not completely "trap" like the ARIA modal example describes.

    That is because example on the W3 guide do have custom javascript to trap use focus on the dialog. You can see the same is mentioned in the comment as well:

    ...
    
    // Bracket the dialog node with two invisible, focusable nodes.
    // While this dialog is open, we use these to make sure that focus never
    // leaves the document even if dialogNode is the first or last node.
    var preDiv = document.createElement('div');
    this.preNode = this.dialogNode.parentNode.insertBefore(preDiv, this.dialogNode);
    this.preNode.tabIndex = 0;
    var postDiv = document.createElement('div');
    this.postNode = this.dialogNode.parentNode.insertBefore(postDiv, this.dialogNode.nextSibling);
    this.postNode.tabIndex = 0;
    
    ...
    

    What's going on here. Is MDN's example incomplete?

    I wouldn't say it is incomplete, but both guides are addressing different audience, w3 document you mentioned is a guide for accessibility while MDN document is just a document describing dialog in HTML spec.

    Would a web developer need to write additional JS code to truly focus trap in order to use the element in production? Or is it "acceptable" from an accessibility perspective to allow a modal to partially trap the focus as in the example, where the keypress on tab can temporarily escape to browser UI elements.

    I guess that depends on you and your product user. Mostly, it is recommended, from accessibility perspective, to trap user focus inside a dialog and allow a way to close the dialog by means of escape key, close button and cancel button.

    And yes, you will have to add custom code for mouse trapping, either in javascript or in HTML by adding 2 focusable elements as you can see in the example on accessibility guide page you mentioned about.