diff --git a/hydra-gates/scripts/lib/check_aria_hidden_focusable.py b/hydra-gates/scripts/lib/check_aria_hidden_focusable.py new file mode 100644 index 0000000..d27a900 --- /dev/null +++ b/hydra-gates/scripts/lib/check_aria_hidden_focusable.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: EUPL-1.2 +r"""Gate-37 aria-hidden-focusable — an element hidden from assistive tech must +not also be in the tab order (WCAG 2.2 AA SC 4.1.2; axe-core `aria-hidden-focus`). + +The failure this catches is real and serious: keyboard focus lands on a +control that screen readers do not announce, so the user is on "nothing". + +WHY THIS WAS REWRITTEN +---------------------- +The previous implementation treated `tabindex` **with any value** as proof of +focusability: + + echo "${tag}" | grep -qE '(^|[[:space:]])(:?tabindex|v-bind:tabindex)[[:space:]]*=' && _focusable=1 + +`tabindex="-1"` is the attribute that **REMOVES** an element from the tab +order. It is the one value that proves the opposite of what the gate concluded. +So the gate's own subject — "hidden from AT *and still reachable by keyboard*" +— was inverted for every element that had already been fixed. + +The canonical hidden-file-input pattern trips it exactly: + + (nc-vue CnFilesWidget) + +That input is correct. It is hidden from AT, removed from the tab order, and +driven by a visible `