Skip to content

Commit 9269e52

Browse files
committed
fix: use first-token ARIA role semantics per WAI-ARIA 1.2 §4.1 (Copilot review)
1 parent 54757d4 commit 9269e52

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

lib/rules/template-no-noninteractive-tabindex.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,17 @@ function roleStatus(node) {
7777
return 'unknown';
7878
}
7979
const tokens = attr.value.chars.trim().toLowerCase().split(/\s+/u);
80-
return tokens.some((t) => INTERACTIVE_ROLES.has(t)) ? 'interactive' : 'non-interactive';
80+
// First-match: find the first recognized token (interactive or non).
81+
// Unrecognized tokens are skipped per WAI-ARIA 1.2 §4.1.
82+
for (const t of tokens) {
83+
if (INTERACTIVE_ROLES.has(t)) {
84+
return 'interactive';
85+
}
86+
if (roles.has(t)) {
87+
return 'non-interactive'; // first recognized non-interactive token
88+
}
89+
}
90+
return 'non-interactive'; // no recognized tokens — treat as non-interactive
8191
}
8292

8393
/** @type {import('eslint').Rule.RuleModule} */

tests/lib/rules/template-no-noninteractive-tabindex.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ ruleTester.run('template-no-noninteractive-tabindex', rule, {
7575
'<template><span tabindex="-1">text</span></template>',
7676
'<template><section tabindex="-1">scroll target</section></template>',
7777
'<template><div tabindex={{-1}}></div></template>',
78+
79+
// WAI-ARIA 1.2 §4.1 role fallback: unrecognized first token is skipped,
80+
// the next recognized token applies. `button` is interactive → allowed.
81+
'<template><div role="foobar button" tabindex="0"></div></template>',
7882
],
7983
invalid: [
8084
{
@@ -123,6 +127,13 @@ ruleTester.run('template-no-noninteractive-tabindex', rule, {
123127
output: null,
124128
errors: [{ messageId: 'noNonInteractiveTabindex' }],
125129
},
130+
// WAI-ARIA 1.2 §4.1 role fallback: first recognized token wins.
131+
// `region` is non-interactive → flagged; `button` (second token) is ignored.
132+
{
133+
code: '<template><div role="region button" tabindex="0"></div></template>',
134+
output: null,
135+
errors: [{ messageId: 'noNonInteractiveTabindex' }],
136+
},
126137
],
127138
});
128139

0 commit comments

Comments
 (0)