From e47ac65e80aad129ee1853379dc160d1a32d2822 Mon Sep 17 00:00:00 2001 From: Emmanuel Pelletier Date: Thu, 17 Apr 2025 15:26:57 +0200 Subject: [PATCH] gaufre: follow disclosure aria pattern - add aria attributes on load with the gaufre api script so that people already using la gaufre don't necessarely *have* to update their code - add the aria patterns in given code examples/react components. In some cases, our small page load JS code isn't enough: for example on SPAs where gaufre buttons might be loaded after page load. thanks @inseo --- .../integration/src/components/Gaufre.tsx | 2 ++ website/public/api/v1/gaufre.js | 30 +++++++++++++------ website/src/pages/examples/gaufre/html.astro | 6 ++++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/integration/src/components/Gaufre.tsx b/packages/integration/src/components/Gaufre.tsx index 2277477..5c3edae 100644 --- a/packages/integration/src/components/Gaufre.tsx +++ b/packages/integration/src/components/Gaufre.tsx @@ -23,6 +23,8 @@ export const Gaufre = ({ variant }: Props) => { type="button" className={`lasuite-gaufre-btn ${variantClass} lasuite-gaufre-btn--vanilla js-lasuite-gaufre-btn`} title={t("gaufre.label")} + aria-expanded="false" + aria-controls="lasuite-gaufre-popup" > {t("gaufre.label")} diff --git a/website/public/api/v1/gaufre.js b/website/public/api/v1/gaufre.js index ff24aeb..5fbfeb4 100644 --- a/website/public/api/v1/gaufre.js +++ b/website/public/api/v1/gaufre.js @@ -1,5 +1,6 @@ ;(function () { const BUTTON_CLASS = "js-lasuite-gaufre-btn" + const POPUP_ID = "lasuite-gaufre-popup" const DIMENSIONS = { width: 304, height: 352, margin: 8 } let lastFocusedButton = null @@ -9,13 +10,20 @@ if ("requestIdleCallback" in window) { requestIdleCallback(() => { appendPopup() + enhanceButtonsA11y() + }) + } + + const enhanceButtonsA11y = () => { + const buttons = document.querySelectorAll(`.${BUTTON_CLASS}`) + buttons.forEach((b) => { + b.setAttribute("aria-controls", POPUP_ID) + b.setAttribute("aria-expanded", "false") }) } document.body.addEventListener("click", (event) => { if (!event.target.classList || !event.target.classList.contains(BUTTON_CLASS)) { - const buttons = document.querySelectorAll(`.${BUTTON_CLASS}`) - buttons.forEach((b) => b.classList.remove("lasuite--gaufre-opened")) hidePopup() return } @@ -36,7 +44,7 @@ }) window.addEventListener("resize", () => { - const popup = document.querySelector(`#lasuite-gaufre-popup.lasuite--gaufre-opened`) + const popup = document.querySelector(`#${POPUP_ID}.lasuite--gaufre-opened`) if (!popup) { return } @@ -48,8 +56,8 @@ }) const appendPopup = () => { - if (document.querySelector(`#lasuite-gaufre-popup`)) { - return Promise.resolve(document.querySelector(`#lasuite-gaufre-popup`)) + if (document.getElementById(POPUP_ID)) { + return Promise.resolve(document.getElementById(POPUP_ID)) } const scriptTag = document.querySelector(`#lasuite-gaufre-script`) if (!scriptTag) { @@ -59,7 +67,7 @@ return } const popup = document.createElement("div") - popup.id = "lasuite-gaufre-popup" + popup.id = POPUP_ID popup.style.cssText = "display: none !important" const { host, protocol, searchParams, origin } = new URL(scriptTag.src) @@ -183,10 +191,11 @@ } const showPopup = (button) => { - let popup = document.querySelector(`#lasuite-gaufre-popup`) + let popup = document.getElementById(POPUP_ID) const show = (el) => { updatePopupStyle(el, button) el.classList.add("lasuite--gaufre-opened") + button.setAttribute("aria-expanded", "true") lastFocusedButton = button setTimeout(() => { el.querySelector(".js-lagaufre-keyboard-anchor").focus() @@ -200,13 +209,16 @@ } const hidePopup = () => { - const popup = document.querySelector(`#lasuite-gaufre-popup`) + const popup = document.getElementById(POPUP_ID) if (popup) { popup.style.cssText = "display: none !important" popup.classList.remove("lasuite--gaufre-opened") } + document.querySelectorAll(`.${BUTTON_CLASS}`).forEach((b) => { + b.classList.remove("lasuite--gaufre-opened") + b.setAttribute("aria-expanded", "false") + }) if (lastFocusedButton) { - lastFocusedButton.classList.remove("lasuite--gaufre-opened") lastFocusedButton.focus() lastFocusedButton = null } diff --git a/website/src/pages/examples/gaufre/html.astro b/website/src/pages/examples/gaufre/html.astro index dea9aa5..6b9d1f5 100644 --- a/website/src/pages/examples/gaufre/html.astro +++ b/website/src/pages/examples/gaufre/html.astro @@ -62,6 +62,8 @@ import gaufreCssUrl from "@gouvfr-lasuite/integration/dist/css/gaufre.css?url" type="button" class="lasuite-gaufre-btn lasuite-gaufre-btn--vanilla js-lasuite-gaufre-btn" title="Les services de La Suite numérique" + aria-expanded="false" + aria-controls="lasuite-gaufre-popup" > Les services de La Suite numérique @@ -71,6 +73,8 @@ import gaufreCssUrl from "@gouvfr-lasuite/integration/dist/css/gaufre.css?url" type="button" class="lasuite-gaufre-btn lasuite-gaufre-btn--vanilla js-lasuite-gaufre-btn" title="Les services de La Suite numérique" + aria-expanded="false" + aria-controls="lasuite-gaufre-popup" > Les services de La Suite numérique @@ -108,6 +112,8 @@ import gaufreCssUrl from "@gouvfr-lasuite/integration/dist/css/gaufre.css?url" type="button" class="lasuite-gaufre-btn lasuite-gaufre-btn--vanilla js-lasuite-gaufre-btn" title="Les services de La Suite numérique" + aria-expanded="false" + aria-controls="lasuite-gaufre-popup" > Les services de La Suite numérique