{closeButtonToRender}
diff --git a/src/scripts/extensions/clipperInject.ts b/src/scripts/extensions/clipperInject.ts index 8a66cd3d..a493b4ca 100644 --- a/src/scripts/extensions/clipperInject.ts +++ b/src/scripts/extensions/clipperInject.ts @@ -84,6 +84,17 @@ export class ClipperInject extends FrameInjectBase { this.updateUiSizeAttributes(); this.overrideTransformStyles(document.documentElement); + // The clipper frame is now visible; hide page body from assistive technologies + // so that tools like Voice Access do not number background page controls. + // The frame is appended to (not ), so marking + // and inert only hides page content while keeping the clipper iframe accessible. + // aria-hidden removes body from the AT tree; inert also disables pointer events + // so Voice Access cannot enumerate or activate background controls. + if (document.body) { + document.body.setAttribute("aria-hidden", "true"); + document.body.setAttribute("inert", ""); + } + this.logger = new CommunicatorLoggerPure(this.uiCommunicator); this.updatePageInfo(); @@ -316,6 +327,10 @@ export class ClipperInject extends FrameInjectBase { this.uiCommunicator.registerFunction(Constants.FunctionKeys.hideUi, () => { this.frame.style.display = "none"; + if (document.body) { + document.body.removeAttribute("aria-hidden"); + document.body.removeAttribute("inert"); + } }); this.uiCommunicator.registerFunction(Constants.FunctionKeys.refreshPage, () => { @@ -375,6 +390,10 @@ export class ClipperInject extends FrameInjectBase { private toggleClipper() { if (this.frame.style.display === "none") { this.frame.style.display = ""; + if (document.body) { + document.body.setAttribute("aria-hidden", "true"); + document.body.setAttribute("inert", ""); + } } this.uiCommunicator.callRemoteFunction(Constants.FunctionKeys.toggleClipper); } diff --git a/src/tests/clipperUI/mainController_tests.tsx b/src/tests/clipperUI/mainController_tests.tsx index 3ba143f1..0f27f925 100644 --- a/src/tests/clipperUI/mainController_tests.tsx +++ b/src/tests/clipperUI/mainController_tests.tsx @@ -467,6 +467,17 @@ export class MainControllerTests extends TestModule { "The close button should render when the clipper is not clipping to OneNote API"); } }); + + test("The main controller should have role='dialog' and aria-modal='true' for accessibility", () => { + MithrilUtils.mountToFixture(this.defaultComponent); + + let mainController = document.getElementById(Constants.Ids.mainController); + ok(mainController, "The main controller element should exist"); + strictEqual(mainController.getAttribute("role"), "dialog", + "The main controller should have role='dialog' to prevent Voice Access from numbering background controls"); + strictEqual(mainController.getAttribute("aria-modal"), "true", + "The main controller should have aria-modal='true' to mark it as a modal dialog"); + }); } private getMockRequestError(): OneNoteApi.RequestError {