From a8d7a8f846446bfa68af023bc8261c6f5fd2658a Mon Sep 17 00:00:00 2001 From: hippi345 <13539685+hippi345@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:50:05 -0400 Subject: [PATCH] Don't let Bootstrap set aria-expanded on the sidebar click area and backdrop On narrow screens the secondary bar click area and #quarto-sidebar-glass were collapse triggers too, so Bootstrap wrote aria-expanded on them. Have both forward clicks to the real toggle button instead. Fixes #15229 --- news/changelog-1.11.md | 1 + .../website/templates/nav-before-body.ejs | 6 +-- .../projects/website/templates/sidebar.ejs | 2 +- .../website/sidebar-collapse-aria/_quarto.yml | 11 +++++ .../website/sidebar-collapse-aria/about.qmd | 5 +++ .../website/sidebar-collapse-aria/index.qmd | 5 +++ .../tests/html-sidebar-collapse-aria.spec.ts | 45 +++++++++++++++++++ 7 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 tests/docs/playwright/website/sidebar-collapse-aria/_quarto.yml create mode 100644 tests/docs/playwright/website/sidebar-collapse-aria/about.qmd create mode 100644 tests/docs/playwright/website/sidebar-collapse-aria/index.qmd create mode 100644 tests/integration/playwright/tests/html-sidebar-collapse-aria.spec.ts diff --git a/news/changelog-1.11.md b/news/changelog-1.11.md index 1b80a1502a7..c677fc41d06 100644 --- a/news/changelog-1.11.md +++ b/news/changelog-1.11.md @@ -51,6 +51,7 @@ All changes included in 1.11: - ([#15129](https://github.com/quarto-dev/quarto-cli/issues/15129)): Fix default listings rendering an empty, focusable metadata link for posts with no date, author or other listed field to show, flagged by axe-core (`link-name`). - ([#15159](https://github.com/quarto-dev/quarto-cli/issues/15159), [#15160](https://github.com/quarto-dev/quarto-cli/issues/15160)): Fix the `revealjs` speaker view's Layout selector having no accessible name or visible keyboard focus, and its current slide, upcoming slide, time, and notes areas not being named regions. Changing layouts no longer forwards control keys to the slides, and the slide navigation buttons no longer introduce an unrelated complementary landmark. (author: @jooyoungseo) - ([#15211](https://github.com/quarto-dev/quarto-cli/issues/15211)): Fix default and grid listings rendering empty, focusable links when an item description contains a link, flagged by axe-core (`link-name`), a regression introduced in v1.7.7. Links in descriptions are shown as text again, so the whole description links to the item. +- ([#15229](https://github.com/quarto-dev/quarto-cli/issues/15229)): On narrow screens, the secondary bar's click area and the sidebar backdrop no longer get `aria-expanded` when the sidebar opens or closes (axe `aria-allowed-attr`). Both now forward clicks to the sidebar toggle button, so tapping the backdrop also restores headroom. ## Formats diff --git a/src/resources/projects/website/templates/nav-before-body.ejs b/src/resources/projects/website/templates/nav-before-body.ejs index d44cabe5e89..75084329d18 100644 --- a/src/resources/projects/website/templates/nav-before-body.ejs +++ b/src/resources/projects/website/templates/nav-before-body.ejs @@ -71,12 +71,10 @@ const navbarTocRight = nav['toc-location'] === "right" || nav['toc-location'] == <% if (nav.showBreadCrumbs) { %>

- + <% } else { %> - +

<% } %> diff --git a/src/resources/projects/website/templates/sidebar.ejs b/src/resources/projects/website/templates/sidebar.ejs index e152a1bc72a..65a8285c5ca 100644 --- a/src/resources/projects/website/templates/sidebar.ejs +++ b/src/resources/projects/website/templates/sidebar.ejs @@ -97,4 +97,4 @@ <% } %> -
+
diff --git a/tests/docs/playwright/website/sidebar-collapse-aria/_quarto.yml b/tests/docs/playwright/website/sidebar-collapse-aria/_quarto.yml new file mode 100644 index 00000000000..c66fc367564 --- /dev/null +++ b/tests/docs/playwright/website/sidebar-collapse-aria/_quarto.yml @@ -0,0 +1,11 @@ +project: + type: website + +website: + title: "sidebar-collapse-aria" + sidebar: + contents: + - index.qmd + - about.qmd + +format: html diff --git a/tests/docs/playwright/website/sidebar-collapse-aria/about.qmd b/tests/docs/playwright/website/sidebar-collapse-aria/about.qmd new file mode 100644 index 00000000000..efaffe4dde1 --- /dev/null +++ b/tests/docs/playwright/website/sidebar-collapse-aria/about.qmd @@ -0,0 +1,5 @@ +--- +title: "About" +--- + +About page. diff --git a/tests/docs/playwright/website/sidebar-collapse-aria/index.qmd b/tests/docs/playwright/website/sidebar-collapse-aria/index.qmd new file mode 100644 index 00000000000..17325bcf838 --- /dev/null +++ b/tests/docs/playwright/website/sidebar-collapse-aria/index.qmd @@ -0,0 +1,5 @@ +--- +title: "Home" +--- + +Home page. diff --git a/tests/integration/playwright/tests/html-sidebar-collapse-aria.spec.ts b/tests/integration/playwright/tests/html-sidebar-collapse-aria.spec.ts new file mode 100644 index 00000000000..08850a957ed --- /dev/null +++ b/tests/integration/playwright/tests/html-sidebar-collapse-aria.spec.ts @@ -0,0 +1,45 @@ +import { expect, test } from "@playwright/test"; +import { getUrl } from "../src/utils"; + +// On a narrow screen only the sidebar toggle button is a collapse control. +// The click area in the secondary bar and the backdrop behind the open +// sidebar forward their clicks to that button, so Bootstrap must not write +// aria-expanded on them (axe aria-allowed-attr). + +test.use({ viewport: { width: 500, height: 800 } }); + +const url = "website/sidebar-collapse-aria/_site/index.html"; + +test("only the toggle button carries aria-expanded", async ({ page }) => { + await page.goto(getUrl(url), { waitUntil: "load" }); + const toggle = page.locator(".quarto-secondary-nav .quarto-btn-toggle"); + const clickArea = page.locator(".quarto-secondary-nav a.flex-grow-1"); + const glass = page.locator("#quarto-sidebar-glass"); + const sidebar = page.locator("#quarto-sidebar"); + + await expect(toggle).toHaveAttribute("aria-expanded", "false"); + + await toggle.click(); + await expect(sidebar).toHaveClass(/\bshow\b/); + await expect(toggle).toHaveAttribute("aria-expanded", "true"); + await expect(clickArea).not.toHaveAttribute("aria-expanded"); + await expect(glass).not.toHaveAttribute("aria-expanded"); + + // Tapping the backdrop closes the sidebar through the button. + await glass.click({ position: { x: 480, y: 400 } }); + await expect(sidebar).not.toHaveClass(/\bshow\b/); + await expect(toggle).toHaveAttribute("aria-expanded", "false"); + await expect(clickArea).not.toHaveAttribute("aria-expanded"); + await expect(glass).not.toHaveAttribute("aria-expanded"); +}); + +test("the secondary bar click area opens the sidebar", async ({ page }) => { + await page.goto(getUrl(url), { waitUntil: "load" }); + const toggle = page.locator(".quarto-secondary-nav .quarto-btn-toggle"); + const clickArea = page.locator(".quarto-secondary-nav a.flex-grow-1"); + + await clickArea.click(); + await expect(page.locator("#quarto-sidebar")).toHaveClass(/\bshow\b/); + await expect(toggle).toHaveAttribute("aria-expanded", "true"); + await expect(clickArea).not.toHaveAttribute("aria-expanded"); +});