Skip to content

Commit 09ac5b4

Browse files
committed
fix(template-no-role-presentation-on-focusable): tighten UNCONDITIONAL_FOCUSABLE_TAGS to HTML §6.6.3 default-focusable list — drop datalist, details, option (none are own focusable areas)
1 parent d48d268 commit 09ac5b4

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

lib/rules/template-no-role-presentation-on-focusable.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,29 @@ function hasPresentationRole(node) {
6969
// focusable by default — clicks on a label forward to its associated control,
7070
// but the label itself isn't in the tab order. So it's excluded here even
7171
// though `isHtmlInteractiveContent` would return true for it.
72+
// Elements whose default rendering creates a focusable area per HTML §6.6.3
73+
// "Focusable area" + the suggested-focusable list in the `tabindex` section
74+
// (https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute):
75+
// - <button>, <select>, <textarea> — form controls
76+
// - <iframe>, <embed> — navigable containers
77+
// - <summary> when first child of <details> — the disclosure widget itself
78+
// Conditionally-focusable elements are checked elsewhere via
79+
// `isHtmlInteractiveContent`: <a>/<area> need `href`; <input> needs a non-Hidden
80+
// `type`; <audio>/<video> need `controls`; <img> needs `usemap`.
81+
//
82+
// Intentionally NOT in this set, per spec:
83+
// - <details> — its disclosure focus lives on the first <summary> child, not
84+
// the details element itself.
85+
// - <option> — focus stays on the host <select>; option is not its own
86+
// focusable area.
87+
// - <datalist> — `display: none` in UA stylesheets; a hidden data provider.
7288
const UNCONDITIONAL_FOCUSABLE_TAGS = new Set([
7389
'button',
7490
'select',
7591
'textarea',
7692
'iframe',
7793
'embed',
7894
'summary',
79-
'details',
80-
'option',
81-
'datalist',
8295
]);
8396

8497
// Form-control tags whose `disabled` attribute removes them from the tab order

tests/lib/rules/template-no-role-presentation-on-focusable.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ ruleTester.run('template-no-role-presentation-on-focusable', rule, {
2323
// <input type="hidden"> isn't focusable.
2424
'<template><input type="hidden" role="presentation" /></template>',
2525

26+
// <datalist> is a hidden data provider (display:none in UA stylesheets);
27+
// its options surface inside the associated input's UA popup, not on the
28+
// datalist element itself — it's not a focusable area.
29+
'<template><datalist role="presentation"></datalist></template>',
30+
31+
// <details> itself is not a focusable area per HTML §6.6.3 — its first
32+
// <summary> child is the disclosure focus target. role="presentation" on
33+
// the details element does not trigger the spec's conflict resolution.
34+
'<template><details role="presentation"><summary>Title</summary></details></template>',
35+
36+
// <option> is not its own focusable area; focus stays on the host <select>.
37+
'<template><option role="presentation">Foo</option></template>',
38+
2639
// <a> without href isn't focusable.
2740
'<template><a role="presentation">Not a link</a></template>',
2841

0 commit comments

Comments
 (0)