You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|[template-no-aria-hidden-body](docs/rules/template-no-aria-hidden-body.md)| disallow aria-hidden on body element | 📋 | 🔧 ||
265
-
|[template-no-aria-unsupported-elements](docs/rules/template-no-aria-unsupported-elements.md)| disallow ARIA roles, states, and properties on elements that do not support them | 📋 |||
|[template-no-redundant-role](docs/rules/template-no-redundant-role.md)| disallow redundant role attributes | 📋 | 🔧 ||
280
-
|[template-no-unsupported-role-attributes](docs/rules/template-no-unsupported-role-attributes.md)| disallow ARIA attributes that are not supported by the element role | 📋 | 🔧 ||
281
-
|[template-no-whitespace-within-word](docs/rules/template-no-whitespace-within-word.md)| disallow excess whitespace within words (e.g. "W e l c o m e") | 📋 |||
282
-
|[template-require-aria-activedescendant-tabindex](docs/rules/template-require-aria-activedescendant-tabindex.md)| require non-interactive elements with aria-activedescendant to have tabindex | 📋 | 🔧 ||
283
-
|[template-require-context-role](docs/rules/template-require-context-role.md)| require ARIA roles to be used in appropriate context | 📋 |||
284
-
|[template-require-iframe-title](docs/rules/template-require-iframe-title.md)| require iframe elements to have a title attribute | 📋 |||
285
-
|[template-require-input-label](docs/rules/template-require-input-label.md)| require label for form input elements | 📋 |||
286
-
|[template-require-lang-attribute](docs/rules/template-require-lang-attribute.md)| require lang attribute on html element | 📋 |||
|[template-require-media-caption](docs/rules/template-require-media-caption.md)| require captions for audio and video elements | 📋 |||
289
-
|[template-require-presentational-children](docs/rules/template-require-presentational-children.md)| require presentational elements to only contain presentational children | 📋 |||
290
-
|[template-require-valid-alt-text](docs/rules/template-require-valid-alt-text.md)| require valid alt text for images and other elements | 📋 |||
291
-
|[template-require-valid-form-groups](docs/rules/template-require-valid-form-groups.md)| require grouped form controls to have fieldset/legend or WAI-ARIA group labeling ||||
292
-
|[template-table-groups](docs/rules/template-table-groups.md)| require table elements to use table grouping elements | 📋 |||
|[template-no-aria-hidden-body](docs/rules/template-no-aria-hidden-body.md)| disallow aria-hidden on body element | 📋 | 🔧 ||
265
+
|[template-no-aria-unsupported-elements](docs/rules/template-no-aria-unsupported-elements.md)| disallow ARIA roles, states, and properties on elements that do not support them | 📋 |||
|[template-no-nested-interactive](docs/rules/template-no-nested-interactive.md)| disallow nested interactive elements | 📋 |||
276
+
|[template-no-nested-landmark](docs/rules/template-no-nested-landmark.md)| disallow nested landmark elements | 📋 |||
277
+
|[template-no-noninteractive-tabindex](docs/rules/template-no-noninteractive-tabindex.md)| disallow tabindex on non-interactive elements (elements without interactive native semantics or interactive ARIA role) ||||
278
+
|[template-no-pointer-down-event-binding](docs/rules/template-no-pointer-down-event-binding.md)| disallow pointer down event bindings | 📋 |||
|[template-no-redundant-role](docs/rules/template-no-redundant-role.md)| disallow redundant role attributes | 📋 | 🔧 ||
281
+
|[template-no-unsupported-role-attributes](docs/rules/template-no-unsupported-role-attributes.md)| disallow ARIA attributes that are not supported by the element role | 📋 | 🔧 ||
282
+
|[template-no-whitespace-within-word](docs/rules/template-no-whitespace-within-word.md)| disallow excess whitespace within words (e.g. "W e l c o m e") | 📋 |||
283
+
|[template-require-aria-activedescendant-tabindex](docs/rules/template-require-aria-activedescendant-tabindex.md)| require non-interactive elements with aria-activedescendant to have tabindex | 📋 | 🔧 ||
284
+
|[template-require-context-role](docs/rules/template-require-context-role.md)| require ARIA roles to be used in appropriate context | 📋 |||
285
+
|[template-require-iframe-title](docs/rules/template-require-iframe-title.md)| require iframe elements to have a title attribute | 📋 |||
286
+
|[template-require-input-label](docs/rules/template-require-input-label.md)| require label for form input elements | 📋 |||
287
+
|[template-require-lang-attribute](docs/rules/template-require-lang-attribute.md)| require lang attribute on html element | 📋 |||
|[template-require-media-caption](docs/rules/template-require-media-caption.md)| require captions for audio and video elements | 📋 |||
290
+
|[template-require-presentational-children](docs/rules/template-require-presentational-children.md)| require presentational elements to only contain presentational children | 📋 |||
291
+
|[template-require-valid-alt-text](docs/rules/template-require-valid-alt-text.md)| require valid alt text for images and other elements | 📋 |||
292
+
|[template-require-valid-form-groups](docs/rules/template-require-valid-form-groups.md)| require grouped form controls to have fieldset/legend or WAI-ARIA group labeling ||||
293
+
|[template-table-groups](docs/rules/template-table-groups.md)| require table elements to use table grouping elements | 📋 |||
Adding `tabindex="0"` to a `<div>`, `<section>`, etc. puts it in the keyboard tab order without supplying any keyboard semantics — users reach the element but have no way to operate it, and screen readers announce the tag with no hint of interactivity.
8
+
9
+
If the element is meant to be interactive, give it an explicit ARIA role (`button`, `checkbox`, …) **and** wire up the appropriate keyboard event handlers. If it isn't meant to be interactive, remove the tabindex.
10
+
11
+
`tabindex="-1"` is exempt — it marks an element as programmatically focusable but skipped by the Tab key, the canonical pattern for scroll-to-focus targets, focus restoration, and composite-widget children. See [`template-require-aria-activedescendant-tabindex`](./template-require-aria-activedescendant-tabindex.md).
12
+
13
+
`<canvas>` is always exempt. The HTML spec does not classify `<canvas>` as interactive content, but it is routinely used as an interactive drawing or game surface, and `tabindex` is required to make it keyboard-accessible. Flagging `<canvas tabindex="0">` would produce unhelpful noise for these legitimate use-cases.
14
+
15
+
## Examples
16
+
17
+
This rule **forbids** the following:
18
+
19
+
```gjs
20
+
<template>
21
+
<div tabindex="0"></div>
22
+
<article tabindex="0">Story</article>
23
+
<div role="article" tabindex="0"></div>
24
+
<a tabindex="0">Not a link (missing href)</a>
25
+
</template>
26
+
```
27
+
28
+
This rule **allows** the following:
29
+
30
+
```gjs
31
+
<template>
32
+
{{! Interactive native elements }}
33
+
<button tabindex="0">Click</button>
34
+
<a href="/x" tabindex="0">Link</a>
35
+
<input tabindex="-1" />
36
+
37
+
{{! Non-interactive element with an interactive ARIA role }}
{{! <canvas> — exempted because canvas needs tabindex to be keyboard-accessible }}
52
+
<canvas tabindex="0"></canvas>
53
+
</template>
54
+
```
55
+
56
+
## Options
57
+
58
+
-`roles` (default `["tabpanel"]`) — non-interactive ARIA roles exempted from this rule. Elements carrying one of these roles may have `tabindex` without triggering a flag.
59
+
60
+
The default value (`["tabpanel"]`) matches jsx-a11y's recommended config. The [WAI-ARIA APG Tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) gives panels `tabindex="0"` when the panel's content isn't itself focusable, so keyboard users can page through panels. Flagging tabpanel-with-tabindex as a violation would break the canonical Tabs pattern.
61
+
62
+
Use an empty array (`roles: []`) to disable the default exemption — matching jsx-a11y's strict config. Use a wider list (e.g. `roles: ["tabpanel", "region"]`) to exempt additional roles where your project uses `tabindex` legitimately (scrollable regions, etc.).
0 commit comments