Skip to content

Commit 0b00272

Browse files
committed
fix: treat <audio/video controls> and <object> as interactive for tabindex check
1 parent 7d03e62 commit 0b00272

2 files changed

Lines changed: 29 additions & 0 deletions

File tree

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ function isInteractiveElement(node) {
8989
if (tag === 'a' && findAttr(node, 'href')) {
9090
return true;
9191
}
92+
// <audio>/<video> expose interactive UI only when `controls` is present.
93+
// Matches template-no-invalid-interactive.
94+
if ((tag === 'audio' || tag === 'video') && findAttr(node, 'controls')) {
95+
return true;
96+
}
97+
// <object> maps to an embedded-widget role (axobject-query treats embedded
98+
// content as a widget); authors legitimately put tabindex on it to include
99+
// plugin content in the tab order.
100+
if (tag === 'object') {
101+
return true;
102+
}
92103
return false;
93104
}
94105

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ ruleTester.run('template-no-noninteractive-tabindex', rule, {
2020
'<template><input tabindex="-1" /></template>',
2121
'<template><select tabindex="0"></select></template>',
2222

23+
// <audio>/<video> with `controls` render an interactive UI.
24+
'<template><audio controls tabindex="0"></audio></template>',
25+
'<template><video controls tabindex="0"></video></template>',
26+
27+
// <object> is a widget per axobject-query — allow tabindex.
28+
'<template><object tabindex="0"></object></template>',
29+
2330
// Non-interactive element made interactive via role.
2431
'<template><div role="button" tabindex="0"></div></template>',
2532
'<template><div role="checkbox" tabindex="0" aria-checked="false"></div></template>',
@@ -70,6 +77,17 @@ ruleTester.run('template-no-noninteractive-tabindex', rule, {
7077
output: null,
7178
errors: [{ messageId: 'noNonInteractiveTabindex' }],
7279
},
80+
// <audio>/<video> without `controls` have no interactive UI — still flag.
81+
{
82+
code: '<template><audio tabindex="0"></audio></template>',
83+
output: null,
84+
errors: [{ messageId: 'noNonInteractiveTabindex' }],
85+
},
86+
{
87+
code: '<template><video tabindex="0"></video></template>',
88+
output: null,
89+
errors: [{ messageId: 'noNonInteractiveTabindex' }],
90+
},
7391
],
7492
});
7593

0 commit comments

Comments
 (0)