diff --git a/docs/rules/template-require-aria-activedescendant-tabindex.md b/docs/rules/template-require-aria-activedescendant-tabindex.md index 4a4be8d807..155e50ce8d 100644 --- a/docs/rules/template-require-aria-activedescendant-tabindex.md +++ b/docs/rules/template-require-aria-activedescendant-tabindex.md @@ -6,11 +6,11 @@ -This rule requires all non-interactive HTML elements using the `aria-activedescendant` attribute to declare a `tabindex` of zero. +This rule requires non-interactive HTML elements using the `aria-activedescendant` attribute to declare a `tabindex` of `0` or `-1`. The `aria-activedescendant` attribute identifies the active descendant element of a composite widget, textbox, group, or application with document focus. This attribute is placed on the container element of the input control, and its value is set to the ID of the active child element. This allows screen readers to communicate information about the currently active element as if it has focus, while actual focus of the DOM remains on the container element. -Elements with `aria-activedescendant` must have a `tabindex` of zero in order to support keyboard navigation. Besides interactive elements, which are inherently keyboard-focusable, elements using the `aria-activedescendant` attribute must declare a `tabIndex` of zero with the `tabIndex` attribute. +Elements with `aria-activedescendant` must be focusable to support keyboard navigation. `tabindex="0"` puts the element in the natural tab order; `tabindex="-1"` makes it focusable programmatically (e.g. via roving focus) but skips it in the tab order. Both are valid patterns for composite widgets — see the [W3C APG — Managing focus in composites using aria-activedescendant](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_activedescendant). ## Examples @@ -19,8 +19,8 @@ This rule **forbids** the following: ```gjs ``` @@ -32,9 +32,11 @@ This rule **allows** the following:
+
+ ``` diff --git a/lib/rules/template-require-aria-activedescendant-tabindex.js b/lib/rules/template-require-aria-activedescendant-tabindex.js index 7bed6e89aa..27e1cdf897 100644 --- a/lib/rules/template-require-aria-activedescendant-tabindex.js +++ b/lib/rules/template-require-aria-activedescendant-tabindex.js @@ -91,7 +91,7 @@ module.exports = { const tabindexValue = getTabindexNumericValue(tabindexAttr); - if (!Number.isFinite(tabindexValue) || tabindexValue < 0) { + if (!Number.isFinite(tabindexValue) || tabindexValue < -1) { context.report({ node, messageId: 'missingTabindex', diff --git a/tests/lib/rules/template-require-aria-activedescendant-tabindex.js b/tests/lib/rules/template-require-aria-activedescendant-tabindex.js index cbacfb2e53..c430611934 100644 --- a/tests/lib/rules/template-require-aria-activedescendant-tabindex.js +++ b/tests/lib/rules/template-require-aria-activedescendant-tabindex.js @@ -13,6 +13,12 @@ const validHbs = [ '', '', '', + // tabindex="-1" is focusable-but-not-tabbable — the canonical pattern for + // composite widgets that manage focus via roving focus / aria-activedescendant. + // See W3C APG — https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_activedescendant + '
', + '
', + '', ]; const invalidHbs = [ @@ -26,11 +32,6 @@ const invalidHbs = [ output: '
', errors: [{ message: ERROR_MESSAGE }], }, - { - code: '
', - output: '
', - errors: [{ message: ERROR_MESSAGE }], - }, { code: '
', output: '
', @@ -41,11 +42,6 @@ const invalidHbs = [ output: '', errors: [{ message: ERROR_MESSAGE }], }, - { - code: '', - output: '', - errors: [{ message: ERROR_MESSAGE }], - }, ]; function wrapTemplate(entry) {