From cc08a574837dccaf463de3c8c8d9a17bdf2ab5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 19:33:14 +0100 Subject: [PATCH 1/2] fix(Modal): remove aria-hidden when unmount The component adds the aria-hidden attribute to its siblings when open and removes it when closed. However, if the component is mounted as open but then directly unmounted, its siblings will remain hidden from the accessibility API forever. Thus, the logic for removing these attributes is now also triggered when the component is unmounted. --- .../react-core/src/components/Modal/Modal.tsx | 1 + .../components/Modal/__tests__/Modal.test.tsx | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/packages/react-core/src/components/Modal/Modal.tsx b/packages/react-core/src/components/Modal/Modal.tsx index 24013b3fa22..cdaf1764720 100644 --- a/packages/react-core/src/components/Modal/Modal.tsx +++ b/packages/react-core/src/components/Modal/Modal.tsx @@ -212,6 +212,7 @@ export class Modal extends React.Component { } target.removeEventListener('keydown', this.handleEscKeyClick, false); target.classList.remove(css(styles.backdropOpen)); + this.toggleSiblingsFromScreenReaders(false); } render() { diff --git a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx index a7f6c9ec046..f0f2f2d9936 100644 --- a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx @@ -19,6 +19,26 @@ const props = { children: 'modal content' }; +const target = document.createElement('div'); + +const ModalWithSiblings = () => { + const [isOpen, setIsOpen] = React.useState(true); + const [isModalMounted, setIsModalMounted] = React.useState(true); + const modalProps = { ...props, isOpen, appendTo: target, onClose: () => setIsOpen(false) }; + + return ( + <> + +
Section sibling
+ {isModalMounted && ( + + + + )} + + ); +}; + describe('Modal', () => { test('Modal creates a container element once for div', () => { render(); @@ -89,6 +109,51 @@ describe('Modal', () => { expect(consoleErrorMock).toHaveBeenCalled(); }); + test('modal adds aria-hidden attribute to its siblings when open', () => { + render(, { container: document.body.appendChild(target) }); + + const asideSibling = screen.getByRole('complementary', { hidden: true }); + const articleSibling = screen.getByRole('article', { hidden: true }); + + expect(asideSibling).toHaveAttribute('aria-hidden'); + expect(articleSibling).toHaveAttribute('aria-hidden'); + }); + + test('modal removes the aria-hidden attribute from its siblings when closed', async () => { + const user = userEvent.setup(); + + render(, { container: document.body.appendChild(target) }); + + const asideSibling = screen.getByRole('complementary', { hidden: true }); + const articleSibling = screen.getByRole('article', { hidden: true }); + const closeButton = screen.getByRole('button', { name: 'Close' }); + + expect(articleSibling).toHaveAttribute('aria-hidden'); + expect(asideSibling).toHaveAttribute('aria-hidden'); + + await user.click(closeButton); + + expect(articleSibling).not.toHaveAttribute('aria-hidden'); + expect(asideSibling).not.toHaveAttribute('aria-hidden'); + }); + + test('modal removes the aria-hidden attribute from its siblings when unmounted', async () => { + const user = userEvent.setup(); + + render(, { container: document.body.appendChild(target) }); + + const asideSibling = screen.getByRole('complementary', { hidden: true }); + const articleSibling = screen.getByRole('article', { hidden: true }); + const unmountButton = screen.getByRole('button', { name: 'Unmount Modal' }); + + expect(asideSibling).toHaveAttribute('aria-hidden'); + expect(articleSibling).toHaveAttribute('aria-hidden'); + + await user.click(unmountButton); + + expect(asideSibling).not.toHaveAttribute('aria-hidden'); + expect(articleSibling).not.toHaveAttribute('aria-hidden'); + }); test('The modalBoxBody has no aria-label when bodyAriaLabel is not passed', () => { const props = { isOpen: true From 4a86c93b8f3b9752510d1c1814c138a52f682a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 22:42:09 +0100 Subject: [PATCH 2/2] fix(Modal): remove trailing spaces in test file --- .../react-core/src/components/Modal/__tests__/Modal.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx index f0f2f2d9936..d55aa48925a 100644 --- a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx @@ -47,7 +47,7 @@ describe('Modal', () => { test('modal closes with escape', async () => { const user = userEvent.setup(); - + render(); await user.type(screen.getByText(props.title), `{${KeyTypes.Escape}}`);