Skip to main content
No Result Found

modal-readability-outside

Severity: Serious

Description

If screen readers read elements outside the modal when a modal is open, users can get confused about performing the required action on the modal.

This rule ensures that screen readers can’t read any content outside the modal when a modal is open.

To comply with this rule, you can assign aria-hidden=true to the elements outside the modal and aria-modal="true" to the element containing the modal when the modal is open. When the modal is closed, remove aria-hidden=true from the elements for screen readers to access them.

Example

Consider the following example in which a modal is opened without setting aria-hidden=true to the elements outside the modal or setting aria-modal="true" to the element containing the modal.

Incorrect code sample
Copy icon Copy
// Get modal element
const modal = document.getElementById("myModal");
// Get button that opens the modal
const btn = document.getElementById("openModalBtn");
// Get the <span> element that closes the modal
const span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function() {
  modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
  modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target === modal) {
    modal.style.display = "none";
  }
}

Without dynamically handling aria-hidden or aria-modal attributes, screen readers can read elements outside the modal even when the modal is open. This breaks the modal-readability-outside rule.

In contrast, the following example dynamically sets aria-hidden=true to the elements outside the modal and aria-modal="true" to the element containing the modal when the modal is open. When the modal is closed, the aria-hidden attribute is hidden.

Correct code sample
Copy icon Copy
// Get modal element
const modal = document.getElementById("myModal");
// Get main content to toggle aria-hidden
const mainContent = document.getElementById("mainContent");
// Get button that opens the modal
const btn = document.getElementById("openModalBtn");
// Get the <span> element that closes the modal
const closeBtn = document.getElementsByClassName("close")[0];
// Function to hide content from screen readers and show modal
function openModal() {
  modal.style.display = "block";
  mainContent.setAttribute("aria-hidden", "true");  // Hide main content
  modal.setAttribute("aria-modal", "true");  // Set aria-modal to true
}
// Function to show content to screen readers and hide modal
function closeModal() {
  modal.style.display = "none";
  mainContent.removeAttribute("aria-hidden");  // Show main content
  modal.removeAttribute("aria-modal");  // Remove aria-modal attribute
}
// When the user clicks the button, open the modal
btn.onclick = function() {
  openModal();
}
// When the user clicks on <span> (x), close the modal
closeBtn.onclick = function() {
  closeModal();
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target === modal) {
    closeModal();
  }
}
// Helper function to set aria-hidden on all siblings except modal
function setAriaHiddenForSiblings(hidden) {
  const siblings = Array.from(document.body.children).filter((child) => 
    child !== modal && child.tagName !== 'SCRIPT' && child.tagName !== 'STYLE'
  );
  
  siblings.forEach(sibling => {
    if (hidden) {
      sibling.setAttribute('aria-hidden', 'true');
    } else {
      sibling.removeAttribute('aria-hidden');
    }
  });
}
// Override openModal and closeModal to handle aria-hidden on all siblings
function openModal() {
  modal.style.display = "block";
  setAriaHiddenForSiblings(true);  // Hide all sibling elements except modal
  modal.setAttribute("aria-modal", "true");  // Set aria-modal to true
}
function closeModal() {
  modal.style.display = "none";
  setAriaHiddenForSiblings(false);  // Remove aria-hidden from sibling elements
  modal.removeAttribute("aria-modal");  // Remove aria-modal attribute
}

Screen readers can’t read elements outside the modal in this scenario when the modal is open. Thus, this modified code does not violate the modal-readability-outside rule.

How to fix?

Follow these steps to fix the modal-readability-outside rule if it gets flagged:

  • Identify any modals used on your webpage.
  • Check if you have programmed aria-hidden=true to the elements outside the modal and aria-modal="true" to the element containing the modal when the modal is open.
  • If not, modify the JavaScript code to dynamically assign aria-hidden=true to the elements outside the modal and aria-modal="true" to the element containing the modal when the modal is open.
  • Modify the JavaScript code to dynamically remove aria-hidden=true from the elements when the modal is closed so that screen readers can access them.

Reference

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback

Is this page helping you?

Yes
No

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback!

Talk to an Expert
Download Copy Check Circle