Skip to content

Commit 4090836

Browse files
committed
[Modal] Never hide an aria-hidden ancestor of the modal
ariaHiddenSiblings skipped hiding a container child if it contained the modal, so a non-portaled modal (disablePortal) whose DOM node lives inside one of the container's children is no longer rendered inside an aria-hidden ancestor. Previously the container's children were hidden unconditionally, making such modals inaccessible to assistive tech.
1 parent eb8e990 commit 4090836

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

packages/mui-material/src/Modal/ModalManager.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,20 @@ describe('ModalManager', () => {
350350
expect(modal2).not.toBeInaccessible();
351351
});
352352

353+
it('should not add aria-hidden to container siblings that contain the modal', () => {
354+
// Simulates a non-portaled modal (disablePortal) whose DOM node is nested
355+
// inside one of the container's children. Hiding that child would make the
356+
// modal itself inaccessible.
357+
const nestedParent = document.createElement('div');
358+
const nestedModalRef = document.createElement('div');
359+
nestedParent.appendChild(nestedModalRef);
360+
container2.appendChild(nestedParent);
361+
362+
modalManager.add({ ...getDummyModal(), modalRef: nestedModalRef }, container2);
363+
364+
expect(nestedParent).not.toBeInaccessible();
365+
});
366+
353367
it('should add aria-hidden to container siblings', () => {
354368
const secondSibling = document.createElement('input');
355369
container2.appendChild(secondSibling);

packages/mui-material/src/Modal/ModalManager.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ function ariaHiddenSiblings(
6666
[].forEach.call(container.children, (element: Element) => {
6767
const isNotExcludedElement = !blacklist.includes(element);
6868
const isNotForbiddenElement = !isAriaHiddenForbiddenOnElement(element);
69-
if (isNotExcludedElement && isNotForbiddenElement) {
69+
// Never hide an element that contains the modal, otherwise the modal itself
70+
// becomes inaccessible. This happens when the modal is not portaled into the
71+
// container, for example when `disablePortal` is used.
72+
const isNotModalAncestor = currentElement ? !element.contains(currentElement) : true;
73+
if (isNotExcludedElement && isNotForbiddenElement && isNotModalAncestor) {
7074
ariaHidden(element, hide);
7175
}
7276
});

0 commit comments

Comments
 (0)