@arcaauth/eslint-plugin-jsx-a11y 6.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +17 -0
- package/.eslintrc +44 -0
- package/CHANGELOG.md +774 -0
- package/LICENSE.md +8 -0
- package/README.md +423 -0
- package/__mocks__/IdentifierMock.js +15 -0
- package/__mocks__/JSXAttributeMock.js +39 -0
- package/__mocks__/JSXElementMock.js +37 -0
- package/__mocks__/JSXExpressionContainerMock.js +15 -0
- package/__mocks__/JSXSpreadAttributeMock.js +18 -0
- package/__mocks__/JSXTextMock.js +17 -0
- package/__mocks__/LiteralMock.js +17 -0
- package/__mocks__/genInteractives.js +218 -0
- package/__tests__/__util__/axeMapping.js +6 -0
- package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
- package/__tests__/__util__/helpers/parsers.js +186 -0
- package/__tests__/__util__/parserOptionsMapper.js +53 -0
- package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
- package/__tests__/index-test.js +40 -0
- package/__tests__/src/rules/accessible-emoji-test.js +66 -0
- package/__tests__/src/rules/alt-text-test.js +291 -0
- package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
- package/__tests__/src/rules/anchor-has-content-test.js +54 -0
- package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
- package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
- package/__tests__/src/rules/aria-props-test.js +69 -0
- package/__tests__/src/rules/aria-proptypes-test.js +311 -0
- package/__tests__/src/rules/aria-role-test.js +118 -0
- package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
- package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
- package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
- package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
- package/__tests__/src/rules/heading-has-content-test.js +85 -0
- package/__tests__/src/rules/html-has-lang-test.js +42 -0
- package/__tests__/src/rules/iframe-has-title-test.js +55 -0
- package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
- package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
- package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
- package/__tests__/src/rules/label-has-for-test.js +235 -0
- package/__tests__/src/rules/lang-test.js +59 -0
- package/__tests__/src/rules/media-has-caption-test.js +220 -0
- package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
- package/__tests__/src/rules/no-access-key-test.js +48 -0
- package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
- package/__tests__/src/rules/no-autofocus-test.js +68 -0
- package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
- package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
- package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
- package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
- package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
- package/__tests__/src/rules/no-onchange-test.js +57 -0
- package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
- package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
- package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
- package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
- package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
- package/__tests__/src/rules/scope-test.js +50 -0
- package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
- package/__tests__/src/util/attributesComparator-test.js +91 -0
- package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
- package/__tests__/src/util/getComputedRole-test.js +71 -0
- package/__tests__/src/util/getElementType-test.js +154 -0
- package/__tests__/src/util/getExplicitRole-test.js +35 -0
- package/__tests__/src/util/getImplicitRole-test.js +25 -0
- package/__tests__/src/util/getSuggestion-test.js +33 -0
- package/__tests__/src/util/getTabIndex-test.js +85 -0
- package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
- package/__tests__/src/util/implicitRoles/input-test.js +87 -0
- package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
- package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
- package/__tests__/src/util/isAbstractRole-test.js +51 -0
- package/__tests__/src/util/isContentEditable-test.js +52 -0
- package/__tests__/src/util/isDOMElement-test.js +30 -0
- package/__tests__/src/util/isDisabledElement-test.js +88 -0
- package/__tests__/src/util/isFocusable-test.js +111 -0
- package/__tests__/src/util/isInteractiveElement-test.js +104 -0
- package/__tests__/src/util/isInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
- package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
- package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
- package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
- package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
- package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
- package/__tests__/src/util/schemas-test.js +35 -0
- package/docs/rules/accessible-emoji.md +30 -0
- package/docs/rules/alt-text.md +168 -0
- package/docs/rules/anchor-ambiguous-text.md +91 -0
- package/docs/rules/anchor-has-content.md +64 -0
- package/docs/rules/anchor-is-valid.md +270 -0
- package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
- package/docs/rules/aria-props.md +29 -0
- package/docs/rules/aria-proptypes.md +30 -0
- package/docs/rules/aria-role.md +51 -0
- package/docs/rules/aria-unsupported-elements.md +30 -0
- package/docs/rules/autocomplete-valid.md +49 -0
- package/docs/rules/click-events-have-key-events.md +28 -0
- package/docs/rules/control-has-associated-label.md +113 -0
- package/docs/rules/heading-has-content.md +67 -0
- package/docs/rules/html-has-lang.md +31 -0
- package/docs/rules/iframe-has-title.md +37 -0
- package/docs/rules/img-redundant-alt.md +48 -0
- package/docs/rules/interactive-supports-focus.md +156 -0
- package/docs/rules/label-has-associated-control.md +152 -0
- package/docs/rules/label-has-for.md +130 -0
- package/docs/rules/lang.md +31 -0
- package/docs/rules/media-has-caption.md +48 -0
- package/docs/rules/mouse-events-have-key-events.md +58 -0
- package/docs/rules/no-access-key.md +30 -0
- package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
- package/docs/rules/no-autofocus.md +43 -0
- package/docs/rules/no-distracting-elements.md +41 -0
- package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
- package/docs/rules/no-noninteractive-element-interactions.md +145 -0
- package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
- package/docs/rules/no-noninteractive-tabindex.md +115 -0
- package/docs/rules/no-onchange.md +36 -0
- package/docs/rules/no-redundant-roles.md +46 -0
- package/docs/rules/no-static-element-interactions.md +114 -0
- package/docs/rules/prefer-tag-over-role.md +32 -0
- package/docs/rules/role-has-required-aria-props.md +31 -0
- package/docs/rules/role-supports-aria-props.md +39 -0
- package/docs/rules/scope.md +30 -0
- package/docs/rules/tabindex-no-positive.md +32 -0
- package/lib/configs/flat-config-base.js +11 -0
- package/lib/configs/legacy-config-base.js +9 -0
- package/lib/index.js +209 -0
- package/lib/rules/accessible-emoji.js +63 -0
- package/lib/rules/alt-text.js +218 -0
- package/lib/rules/anchor-ambiguous-text.js +64 -0
- package/lib/rules/anchor-has-content.js +60 -0
- package/lib/rules/anchor-is-valid.js +122 -0
- package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
- package/lib/rules/aria-props.js +59 -0
- package/lib/rules/aria-proptypes.js +114 -0
- package/lib/rules/aria-role.js +89 -0
- package/lib/rules/aria-unsupported-elements.js +64 -0
- package/lib/rules/autocomplete-valid.js +67 -0
- package/lib/rules/click-events-have-key-events.js +68 -0
- package/lib/rules/control-has-associated-label.js +103 -0
- package/lib/rules/heading-has-content.js +61 -0
- package/lib/rules/html-has-lang.js +50 -0
- package/lib/rules/iframe-has-title.js +50 -0
- package/lib/rules/img-redundant-alt.js +88 -0
- package/lib/rules/interactive-supports-focus.js +87 -0
- package/lib/rules/label-has-associated-control.js +127 -0
- package/lib/rules/label-has-for.js +150 -0
- package/lib/rules/lang.js +68 -0
- package/lib/rules/media-has-caption.js +96 -0
- package/lib/rules/mouse-events-have-key-events.js +94 -0
- package/lib/rules/no-access-key.js +43 -0
- package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
- package/lib/rules/no-autofocus.js +62 -0
- package/lib/rules/no-distracting-elements.js +54 -0
- package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
- package/lib/rules/no-noninteractive-element-interactions.js +95 -0
- package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
- package/lib/rules/no-noninteractive-tabindex.js +109 -0
- package/lib/rules/no-onchange.js +52 -0
- package/lib/rules/no-redundant-roles.js +86 -0
- package/lib/rules/no-static-element-interactions.js +102 -0
- package/lib/rules/prefer-tag-over-role.js +75 -0
- package/lib/rules/role-has-required-aria-props.js +88 -0
- package/lib/rules/role-supports-aria-props.js +78 -0
- package/lib/rules/scope.js +58 -0
- package/lib/rules/tabindex-no-positive.js +53 -0
- package/lib/util/attributesComparator.js +34 -0
- package/lib/util/getAccessibleChildText.js +55 -0
- package/lib/util/getComputedRole.js +19 -0
- package/lib/util/getElementType.js +30 -0
- package/lib/util/getExplicitRole.js +27 -0
- package/lib/util/getImplicitRole.js +24 -0
- package/lib/util/getSuggestion.js +32 -0
- package/lib/util/getTabIndex.js +34 -0
- package/lib/util/hasAccessibleChild.js +30 -0
- package/lib/util/implicitRoles/a.js +17 -0
- package/lib/util/implicitRoles/area.js +17 -0
- package/lib/util/implicitRoles/article.js +13 -0
- package/lib/util/implicitRoles/aside.js +13 -0
- package/lib/util/implicitRoles/body.js +13 -0
- package/lib/util/implicitRoles/button.js +13 -0
- package/lib/util/implicitRoles/datalist.js +13 -0
- package/lib/util/implicitRoles/details.js +13 -0
- package/lib/util/implicitRoles/dialog.js +13 -0
- package/lib/util/implicitRoles/form.js +13 -0
- package/lib/util/implicitRoles/h1.js +13 -0
- package/lib/util/implicitRoles/h2.js +13 -0
- package/lib/util/implicitRoles/h3.js +13 -0
- package/lib/util/implicitRoles/h4.js +13 -0
- package/lib/util/implicitRoles/h5.js +13 -0
- package/lib/util/implicitRoles/h6.js +13 -0
- package/lib/util/implicitRoles/hr.js +13 -0
- package/lib/util/implicitRoles/img.js +31 -0
- package/lib/util/implicitRoles/index.js +82 -0
- package/lib/util/implicitRoles/input.js +38 -0
- package/lib/util/implicitRoles/li.js +13 -0
- package/lib/util/implicitRoles/link.js +17 -0
- package/lib/util/implicitRoles/menu.js +19 -0
- package/lib/util/implicitRoles/menuitem.js +28 -0
- package/lib/util/implicitRoles/meter.js +13 -0
- package/lib/util/implicitRoles/nav.js +13 -0
- package/lib/util/implicitRoles/ol.js +13 -0
- package/lib/util/implicitRoles/option.js +13 -0
- package/lib/util/implicitRoles/output.js +13 -0
- package/lib/util/implicitRoles/progress.js +13 -0
- package/lib/util/implicitRoles/section.js +13 -0
- package/lib/util/implicitRoles/select.js +13 -0
- package/lib/util/implicitRoles/tbody.js +13 -0
- package/lib/util/implicitRoles/textarea.js +13 -0
- package/lib/util/implicitRoles/tfoot.js +13 -0
- package/lib/util/implicitRoles/thead.js +13 -0
- package/lib/util/implicitRoles/ul.js +13 -0
- package/lib/util/isAbstractRole.js +23 -0
- package/lib/util/isContentEditable.js +13 -0
- package/lib/util/isDOMElement.js +15 -0
- package/lib/util/isDisabledElement.js +23 -0
- package/lib/util/isFocusable.js +23 -0
- package/lib/util/isHiddenFromScreenReader.js +26 -0
- package/lib/util/isInteractiveElement.js +116 -0
- package/lib/util/isInteractiveRole.js +54 -0
- package/lib/util/isNonInteractiveElement.js +131 -0
- package/lib/util/isNonInteractiveRole.js +55 -0
- package/lib/util/isNonLiteralProperty.js +29 -0
- package/lib/util/isPresentationRole.js +13 -0
- package/lib/util/isSemanticRoleElement.js +54 -0
- package/lib/util/mayContainChildComponent.js +50 -0
- package/lib/util/mayHaveAccessibleLabel.js +95 -0
- package/lib/util/schemas.js +52 -0
- package/package.json +120 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# jsx-a11y/aria-proptypes
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
ARIA state and property values must be valid.
|
|
8
|
+
|
|
9
|
+
## Rule details
|
|
10
|
+
|
|
11
|
+
This rule takes no arguments.
|
|
12
|
+
|
|
13
|
+
### Succeed
|
|
14
|
+
```jsx
|
|
15
|
+
<!-- Good: the aria-hidden state is of type true/false -->
|
|
16
|
+
<span aria-hidden="true">foo</span>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Fail
|
|
20
|
+
```jsx
|
|
21
|
+
<!-- Bad: the aria-hidden state is of type true/false -->
|
|
22
|
+
<span aria-hidden="yes">foo</span>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Accessibility guidelines
|
|
26
|
+
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
|
|
27
|
+
|
|
28
|
+
### Resources
|
|
29
|
+
- [ARIA Spec, States and Properties](https://www.w3.org/TR/wai-aria/#states_and_properties)
|
|
30
|
+
- [Chrome Audit Rules, AX_ARIA_04](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_04)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# jsx-a11y/aria-role
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Elements with ARIA roles must use a valid, non-abstract ARIA role. A reference to role definitions can be found at [WAI-ARIA](https://www.w3.org/TR/wai-aria/#role_definitions) site.
|
|
8
|
+
|
|
9
|
+
## Rule options
|
|
10
|
+
|
|
11
|
+
This rule takes one optional object argument of type object:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"rules": {
|
|
16
|
+
"jsx-a11y/aria-role": [ 2, {
|
|
17
|
+
"allowedInvalidRoles": ["text"],
|
|
18
|
+
"ignoreNonDOM": true
|
|
19
|
+
}],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`allowedInvalidRules` is an optional string array of custom roles that should be allowed in addition to the ARIA spec, such as for cases when you [need to use a non-standard role](https://axesslab.com/text-splitting).
|
|
25
|
+
|
|
26
|
+
For the `ignoreNonDOM` option, this determines if developer created components are checked.
|
|
27
|
+
|
|
28
|
+
### Succeed
|
|
29
|
+
```jsx
|
|
30
|
+
<div role="button"></div> <!-- Good: "button" is a valid ARIA role -->
|
|
31
|
+
<div role={role}></div> <!-- Good: role is a variable & cannot be determined until runtime. -->
|
|
32
|
+
<div></div> <!-- Good: No ARIA role -->
|
|
33
|
+
<Foo role={role}></Foo> <!-- Good: ignoreNonDOM is set to true -->
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Fail
|
|
37
|
+
|
|
38
|
+
```jsx
|
|
39
|
+
<div role="datepicker"></div> <!-- Bad: "datepicker" is not an ARIA role -->
|
|
40
|
+
<div role="range"></div> <!-- Bad: "range" is an _abstract_ ARIA role -->
|
|
41
|
+
<div role=""></div> <!-- Bad: An empty ARIA role is not allowed -->
|
|
42
|
+
<Foo role={role}></Foo> <!-- Bad: ignoreNonDOM is set to false or not set -->
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Accessibility guidelines
|
|
46
|
+
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
|
|
47
|
+
|
|
48
|
+
### Resources
|
|
49
|
+
- [Chrome Audit Rules, AX_ARIA_01](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_01)
|
|
50
|
+
- [DPUB-ARIA roles](https://www.w3.org/TR/dpub-aria-1.0/)
|
|
51
|
+
- [MDN: Using ARIA: Roles, states, and properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# jsx-a11y/aria-unsupported-elements
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Certain reserved DOM elements do not support ARIA roles, states and properties. This is often because they are not visible, for example `meta`, `html`, `script`, `style`. This rule enforces that these DOM elements do not contain the `role` and/or `aria-*` props.
|
|
8
|
+
|
|
9
|
+
## Rule details
|
|
10
|
+
|
|
11
|
+
This rule takes no arguments.
|
|
12
|
+
|
|
13
|
+
### Succeed
|
|
14
|
+
```jsx
|
|
15
|
+
<!-- Good: the meta element should not be given any ARIA attributes -->
|
|
16
|
+
<meta charset="UTF-8" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Fail
|
|
20
|
+
```jsx
|
|
21
|
+
<!-- Bad: the meta element should not be given any ARIA attributes -->
|
|
22
|
+
<meta charset="UTF-8" aria-hidden="false" />
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Accessibility guidelines
|
|
26
|
+
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
|
|
27
|
+
|
|
28
|
+
### Resources
|
|
29
|
+
- [Chrome Audit Rules, AX_ARIA_12](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_12)
|
|
30
|
+
- [DPUB-ARIA roles](https://www.w3.org/TR/dpub-aria-1.0/)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# jsx-a11y/autocomplete-valid
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Ensure the autocomplete attribute is correct and suitable for the form field it is used with.
|
|
8
|
+
|
|
9
|
+
## Rule options
|
|
10
|
+
|
|
11
|
+
This rule takes one optional object argument of type object:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
{
|
|
15
|
+
"rules": {
|
|
16
|
+
"jsx-a11y/autocomplete-valid": [ 2, {
|
|
17
|
+
"inputComponents": ["Input", "FormField"]
|
|
18
|
+
}],
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Succeed
|
|
24
|
+
```jsx
|
|
25
|
+
<!-- Good: the autocomplete attribute is used according to the HTML specification -->
|
|
26
|
+
<input type="text" autocomplete="name" />
|
|
27
|
+
|
|
28
|
+
<!-- Good: MyInput is not listed in inputComponents -->
|
|
29
|
+
<MyInput autocomplete="incorrect" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Fail
|
|
33
|
+
```jsx
|
|
34
|
+
<!-- Bad: the autocomplete attribute has an invalid value -->
|
|
35
|
+
<input type="text" autocomplete="incorrect" />
|
|
36
|
+
|
|
37
|
+
<!-- Bad: the autocomplete attribute is on an inappropriate input element -->
|
|
38
|
+
<input type="email" autocomplete="url" />
|
|
39
|
+
|
|
40
|
+
<!-- Bad: MyInput is listed in inputComponents -->
|
|
41
|
+
<MyInput autocomplete="incorrect" />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Accessibility guidelines
|
|
45
|
+
- [WCAG 1.3.5](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose)
|
|
46
|
+
|
|
47
|
+
### Resources
|
|
48
|
+
- [axe-core, autocomplete-valid](https://dequeuniversity.com/rules/axe/3.2/autocomplete-valid)
|
|
49
|
+
- [HTML 5.2, Autocomplete requirements](https://www.w3.org/TR/html52/sec-forms.html#autofilling-form-controls-the-autocomplete-attribute)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# jsx-a11y/click-events-have-key-events
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Enforce `onClick` is accompanied by at least one of the following: `onKeyUp`, `onKeyDown`, `onKeyPress`. Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, AT compatibility, and screen reader users. This does not apply for interactive or hidden elements.
|
|
8
|
+
|
|
9
|
+
## Rule details
|
|
10
|
+
|
|
11
|
+
This rule takes no arguments.
|
|
12
|
+
|
|
13
|
+
### Succeed
|
|
14
|
+
```jsx
|
|
15
|
+
<div onClick={() => {}} onKeyDown={this.handleKeyDown} />
|
|
16
|
+
<div onClick={() => {}} onKeyUp={this.handleKeyUp} />
|
|
17
|
+
<div onClick={() => {}} onKeyPress={this.handleKeyPress} />
|
|
18
|
+
<button onClick={() => {}} />
|
|
19
|
+
<div onClick{() => {}} aria-hidden="true" />
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Fail
|
|
23
|
+
```jsx
|
|
24
|
+
<div onClick={() => {}} />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Accessibility guidelines
|
|
28
|
+
- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# jsx-a11y/control-has-associated-label
|
|
2
|
+
|
|
3
|
+
🚫 This rule is _disabled_ in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Enforce that a control (an interactive element) has a text label.
|
|
8
|
+
|
|
9
|
+
There are two supported ways to supply a control with a text label:
|
|
10
|
+
|
|
11
|
+
- Provide text content inside the element.
|
|
12
|
+
- Use the `aria-label` attribute on the element, with a text value.
|
|
13
|
+
- Use the `aria-labelledby` attribute on the element, and point the IDREF value to an element with an accessible label.
|
|
14
|
+
- Alternatively, with an `img` tag, you may use the `alt` attribute to supply a text description of the image.
|
|
15
|
+
|
|
16
|
+
The rule is permissive in the sense that it will assume that expressions will eventually provide a label. So an element like this will pass.
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
<button type="button">{maybeSomethingThatContainsALabel}</button>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How do I resolve this error?
|
|
23
|
+
|
|
24
|
+
### Case: I have a simple button that requires a label.
|
|
25
|
+
|
|
26
|
+
Provide text content in the `button` element.
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
<button type="button">Save</button>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Case: I have an icon button and I don't want visible text.
|
|
33
|
+
|
|
34
|
+
Use the `aria-label` attribute and provide the text label as the value.
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
<button type="button" aria-label="Save" class="icon-save" />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Case: The label for my element is already located on the page and I don't want to repeat the text in my source code.
|
|
41
|
+
|
|
42
|
+
Use the `aria-labelledby` attribute and point the IDREF value to an element with an accessible label.
|
|
43
|
+
|
|
44
|
+
```jsx
|
|
45
|
+
<div id="js_1">Comment</div>
|
|
46
|
+
<textarea aria-labelledby="js_1"></textarea>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Case: My label and input components are custom components, but I still want to require that they have an accessible text label.
|
|
50
|
+
|
|
51
|
+
You can configure the rule to be aware of your custom components. Refer to the Rule Details below.
|
|
52
|
+
|
|
53
|
+
```jsx
|
|
54
|
+
<CustomInput label="Surname" type="text" value={value} />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Rule options
|
|
58
|
+
|
|
59
|
+
This rule takes one optional object argument of type object:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"rules": {
|
|
64
|
+
"jsx-a11y/control-has-associated-label": [ 2, {
|
|
65
|
+
"labelAttributes": ["label"],
|
|
66
|
+
"controlComponents": ["CustomComponent"],
|
|
67
|
+
"ignoreElements": [
|
|
68
|
+
"audio",
|
|
69
|
+
"canvas",
|
|
70
|
+
"embed",
|
|
71
|
+
"input",
|
|
72
|
+
"textarea",
|
|
73
|
+
"tr",
|
|
74
|
+
"video",
|
|
75
|
+
],
|
|
76
|
+
"ignoreRoles": [
|
|
77
|
+
"grid",
|
|
78
|
+
"listbox",
|
|
79
|
+
"menu",
|
|
80
|
+
"menubar",
|
|
81
|
+
"radiogroup",
|
|
82
|
+
"row",
|
|
83
|
+
"tablist",
|
|
84
|
+
"toolbar",
|
|
85
|
+
"tree",
|
|
86
|
+
"treegrid",
|
|
87
|
+
],
|
|
88
|
+
"depth": 3,
|
|
89
|
+
}],
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- `labelAttributes` is a list of attributes to check on the control component and its children for a label. Use this if you have a custom component that uses a string passed on a prop to render an HTML `label`, for example.
|
|
95
|
+
- `controlComponents` is a list of custom React Components names that will render down to an interactive element.
|
|
96
|
+
- `ignoreElements` is an array of elements that should not be considered control (interactive) elements and therefore they do not require a text label.
|
|
97
|
+
- `ignoreRoles` is an array of ARIA roles that should not be considered control (interactive) roles and therefore they do not require a text label.
|
|
98
|
+
- `depth` (default 2, max 25) is an integer that determines how deep within a `JSXElement` the rule should look for text content or an element with a label to determine if the interactive element will have an accessible label.
|
|
99
|
+
|
|
100
|
+
### Succeed
|
|
101
|
+
```jsx
|
|
102
|
+
<button type="button" aria-label="Save" class="icon-save" />
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Fail
|
|
106
|
+
```jsx
|
|
107
|
+
<button type="button" class="icon-save" />
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Accessibility guidelines
|
|
111
|
+
- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships)
|
|
112
|
+
- [WCAG 3.3.2](https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions)
|
|
113
|
+
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# jsx-a11y/heading-has-content
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Enforce that heading elements (`h1`, `h2`, etc.) have content and that the content is accessible to screen readers. Accessible means that it is not hidden using the `aria-hidden` prop. Refer to the references to learn about why this is important.
|
|
8
|
+
|
|
9
|
+
## Rule options
|
|
10
|
+
|
|
11
|
+
This rule takes one optional object argument of type object:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"rules": {
|
|
16
|
+
"jsx-a11y/heading-has-content": [ 2, {
|
|
17
|
+
"components": [ "MyHeading" ],
|
|
18
|
+
}],
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For the `components` option, these strings determine which JSX elements (**always including** `<h1>` thru `<h6>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `h1` element (like in React):
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
// Header.js
|
|
28
|
+
const Header = props => {
|
|
29
|
+
return (
|
|
30
|
+
<h1 {...props}>{ props.children }</h1>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
// CreateAccount.js (for example)
|
|
37
|
+
...
|
|
38
|
+
return (
|
|
39
|
+
<Header>Create Account</Header>
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Bad
|
|
44
|
+
```jsx
|
|
45
|
+
function Foo(props) {
|
|
46
|
+
return <label {...props} />
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Succeed
|
|
51
|
+
```jsx
|
|
52
|
+
<h1>Heading Content!</h1>
|
|
53
|
+
<h1><TextWrapper /><h1>
|
|
54
|
+
<h1 dangerouslySetInnerHTML={{ __html: 'foo' }} />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Fail
|
|
58
|
+
```jsx
|
|
59
|
+
<h1 />
|
|
60
|
+
<h1><TextWrapper aria-hidden />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Accessibility guidelines
|
|
64
|
+
- [WCAG 2.4.6](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-descriptive.html)
|
|
65
|
+
|
|
66
|
+
### Resources
|
|
67
|
+
- [axe-core, empty-heading](https://dequeuniversity.com/rules/axe/3.2/empty-heading)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# jsx-a11y/html-has-lang
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
<html> elements must have the lang prop. This rule is largely superseded by the [`lang` rule](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/lang.md).
|
|
8
|
+
|
|
9
|
+
## Rule details
|
|
10
|
+
|
|
11
|
+
This rule takes no arguments.
|
|
12
|
+
|
|
13
|
+
### Succeed
|
|
14
|
+
```jsx
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<html lang="en-US">
|
|
17
|
+
<html lang={language}>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Fail
|
|
21
|
+
|
|
22
|
+
```jsx
|
|
23
|
+
<html>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Accessibility guidelines
|
|
27
|
+
- [WCAG 3.1.1](https://www.w3.org/WAI/WCAG21/Understanding/language-of-page)
|
|
28
|
+
|
|
29
|
+
### Resources
|
|
30
|
+
- [axe-core, html-has-lang](https://dequeuniversity.com/rules/axe/3.2/html-has-lang)
|
|
31
|
+
- [axe-core, html-lang-valid](https://dequeuniversity.com/rules/axe/3.2/html-lang-valid)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# jsx-a11y/iframe-has-title
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
`<iframe>` elements must have a unique title property to indicate its content to the user.
|
|
8
|
+
|
|
9
|
+
## Rule details
|
|
10
|
+
|
|
11
|
+
This rule takes no arguments.
|
|
12
|
+
|
|
13
|
+
### Succeed
|
|
14
|
+
```jsx
|
|
15
|
+
<iframe title="This is a unique title" />
|
|
16
|
+
<iframe title={uniqueTitle} />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Fail
|
|
20
|
+
```jsx
|
|
21
|
+
<iframe />
|
|
22
|
+
<iframe {...props} />
|
|
23
|
+
<iframe title="" />
|
|
24
|
+
<iframe title={''} />
|
|
25
|
+
<iframe title={``} />
|
|
26
|
+
<iframe title={undefined} />
|
|
27
|
+
<iframe title={false} />
|
|
28
|
+
<iframe title={true} />
|
|
29
|
+
<iframe title={42} />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Accessibility guidelines
|
|
33
|
+
- [WCAG 2.4.1](https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks)
|
|
34
|
+
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
|
|
35
|
+
|
|
36
|
+
### Resources
|
|
37
|
+
- [axe-core, frame-title](https://dequeuniversity.com/rules/axe/3.2/frame-title)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# jsx-a11y/img-redundant-alt
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Enforce img alt attribute does not contain the word image, picture, or photo. Screen readers already announce `img` elements as an image. There is no need to use words such as *image*, *photo*, and/or *picture*.
|
|
8
|
+
|
|
9
|
+
## Rule options
|
|
10
|
+
|
|
11
|
+
This rule takes one optional object argument of type object:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"rules": {
|
|
16
|
+
"jsx-a11y/img-redundant-alt": [ 2, {
|
|
17
|
+
"components": [ "Image" ],
|
|
18
|
+
"words": [ "Bild", "Foto" ],
|
|
19
|
+
}],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For the `components` option, these strings determine which JSX elements (**always including** `<img>`) should be checked for having redundant words in the `alt` prop value . This is a good use case when you have a wrapper component that simply renders an `img` element (like in React).
|
|
25
|
+
|
|
26
|
+
For the `words` option, these strings can be used to specify custom words that should be checked for in the alt prop, including `image`, `photo`, and `picture`. Useful for specifying words in other languages.
|
|
27
|
+
|
|
28
|
+
The rule will first check if `aria-hidden` is true to determine whether to enforce the rule. If the image is hidden, then rule will always succeed.
|
|
29
|
+
|
|
30
|
+
### Succeed
|
|
31
|
+
```jsx
|
|
32
|
+
<img src="foo" alt="Foo eating a sandwich." />
|
|
33
|
+
<img src="bar" aria-hidden alt="Picture of me taking a photo of an image" /> // Will pass because it is hidden.
|
|
34
|
+
<img src="baz" alt={`Baz taking a ${photo}`} /> // This is valid since photo is a variable name.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Fail
|
|
38
|
+
```jsx
|
|
39
|
+
<img src="foo" alt="Photo of foo being weird." />
|
|
40
|
+
<img src="bar" alt="Image of me at a bar!" />
|
|
41
|
+
<img src="baz" alt="Picture of baz fixing a bug." />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Accessibility guidelines
|
|
45
|
+
General best practice (reference resources)
|
|
46
|
+
|
|
47
|
+
### Resources
|
|
48
|
+
- [WebAIM, Alternative Text](https://webaim.org/techniques/alttext/)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# jsx-a11y/interactive-supports-focus
|
|
2
|
+
|
|
3
|
+
💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Elements with an interactive role and interaction handlers (mouse or key press) must be focusable.
|
|
8
|
+
|
|
9
|
+
## How do I resolve this error?
|
|
10
|
+
|
|
11
|
+
### Case: I got the error "Elements with the '${role}' interactive role must be tabbable". How can I fix this?
|
|
12
|
+
|
|
13
|
+
This element is a stand-alone control like a button, a link or a form element. A user should be able to reach this element by pressing the tab key on their keyboard.
|
|
14
|
+
|
|
15
|
+
Add the `tabIndex` property to your component. A value of zero indicates that this element can be tabbed to.
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
<div
|
|
19
|
+
role="button"
|
|
20
|
+
tabIndex={0} />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
-- or --
|
|
24
|
+
|
|
25
|
+
Replace the component with one that renders semantic html element like `<button>`, `<a href>` or `<input>` -- whichever fits your purpose.
|
|
26
|
+
|
|
27
|
+
Generally buttons, links and form elements should be reachable via tab key presses. An element that can be tabbed to is said to be in the _tab ring_.
|
|
28
|
+
|
|
29
|
+
### Case: I got the error "Elements with the '${role}' interactive role must be focusable". How can I fix this?
|
|
30
|
+
|
|
31
|
+
This element is part of a group of buttons, links, menu items, etc. Or this element is part of a composite widget. Composite widgets prescribe standard [keyboard interaction patterns](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav). Within a group of similar elements -- like a button bar -- or within a composite widget, elements that can be focused are given a tabindex of -1. This makes the element _focusable_ but not _tabbable_. Generally one item in a group should have a tabindex of zero so that a user can tab to the component. Once an element in the component has focus, your key management behaviors will control traversal within the component's pieces. As the UI author, you will need to implement the key handling behaviors such as listening for traversal key (up/down/left/right) presses and moving the page focus between the focusable elements in your widget.
|
|
32
|
+
|
|
33
|
+
```jsx
|
|
34
|
+
<div role="menu">
|
|
35
|
+
<div role="menuitem" tabIndex="0">Open</div>
|
|
36
|
+
<div role="menuitem" tabIndex="-1">Save</div>
|
|
37
|
+
<div role="menuitem" tabIndex="-1">Close</div>
|
|
38
|
+
</div>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
In the example above, the first item in the group can be tabbed to. The developer provides the ability to traverse to the subsequent items via the up/down/left/right arrow keys. Traversing via arrow keys is not provided by the browser or the assistive technology. See [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav) for information about established traversal behaviors for various UI widgets.
|
|
42
|
+
|
|
43
|
+
### Case: This element is not a button, link, menuitem, etc. It is catching bubbled events from elements that it contains
|
|
44
|
+
|
|
45
|
+
If your element is catching bubbled click or key events from descendant elements, then the proper role for this element is `presentation`.
|
|
46
|
+
|
|
47
|
+
```jsx
|
|
48
|
+
<div
|
|
49
|
+
onClick={onClickHandler}
|
|
50
|
+
role="presentation">
|
|
51
|
+
<button>Save</button>
|
|
52
|
+
</div>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Marking an element with the role `presentation` indicates to assistive technology that this element should be ignored; it exists to support the web application and is not meant for humans to interact with directly.
|
|
56
|
+
|
|
57
|
+
## Rule options
|
|
58
|
+
|
|
59
|
+
This rule takes an options object with the key `tabbable`. The value is an array of interactive ARIA roles that should be considered tabbable, not just focusable. Any interactive role not included in this list will be flagged as needing to be focusable (tabindex of -1).
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
{
|
|
63
|
+
'jsx-a11y/interactive-supports-focus': [
|
|
64
|
+
'error',
|
|
65
|
+
{
|
|
66
|
+
tabbable: [
|
|
67
|
+
'button',
|
|
68
|
+
'checkbox',
|
|
69
|
+
'link',
|
|
70
|
+
'searchbox',
|
|
71
|
+
'spinbutton',
|
|
72
|
+
'switch',
|
|
73
|
+
'textbox',
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The recommended options list interactive roles that act as form elements. Generally, elements with a role like `menuitem` are a part of a composite widget. Focus in a composite widget is controlled and moved programmatically to satisfy the prescribed [keyboard interaction pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav) for the widget.
|
|
81
|
+
|
|
82
|
+
The list of possible values includes:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
[
|
|
86
|
+
'button',
|
|
87
|
+
'checkbox',
|
|
88
|
+
'columnheader',
|
|
89
|
+
'combobox',
|
|
90
|
+
'grid',
|
|
91
|
+
'gridcell',
|
|
92
|
+
'link',
|
|
93
|
+
'listbox',
|
|
94
|
+
'menu',
|
|
95
|
+
'menubar',
|
|
96
|
+
'menuitem',
|
|
97
|
+
'menuitemcheckbox',
|
|
98
|
+
'menuitemradio',
|
|
99
|
+
'option',
|
|
100
|
+
'progressbar',
|
|
101
|
+
'radio',
|
|
102
|
+
'radiogroup',
|
|
103
|
+
'row',
|
|
104
|
+
'rowheader',
|
|
105
|
+
'searchbox',
|
|
106
|
+
'slider',
|
|
107
|
+
'spinbutton',
|
|
108
|
+
'switch',
|
|
109
|
+
'tab',
|
|
110
|
+
'tablist',
|
|
111
|
+
'textbox',
|
|
112
|
+
'toolbar',
|
|
113
|
+
'tree',
|
|
114
|
+
'treegrid',
|
|
115
|
+
'treeitem',
|
|
116
|
+
'doc-backlink',
|
|
117
|
+
'doc-biblioref',
|
|
118
|
+
'doc-glossref',
|
|
119
|
+
'doc-noteref',
|
|
120
|
+
]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Succeed
|
|
124
|
+
|
|
125
|
+
```jsx
|
|
126
|
+
<!-- Good: div with onClick attribute is hidden from screen reader -->
|
|
127
|
+
<div aria-hidden onClick={() => void 0} />
|
|
128
|
+
<!-- Good: span with onClick attribute is in the tab order -->
|
|
129
|
+
<span onClick="doSomething();" tabIndex="0" role="button">Click me!</span>
|
|
130
|
+
<!-- Good: span with onClick attribute may be focused programmatically -->
|
|
131
|
+
<span onClick="doSomething();" tabIndex="-1" role="menuitem">Click me too!</span>
|
|
132
|
+
<!-- Good: anchor element with href is inherently focusable -->
|
|
133
|
+
<a href="javascript:void(0);" onClick="doSomething();">Click ALL the things!</a>
|
|
134
|
+
<!-- Good: buttons are inherently focusable -->
|
|
135
|
+
<button onClick="doSomething();">Click the button :)</button>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Fail
|
|
139
|
+
|
|
140
|
+
```jsx
|
|
141
|
+
<!-- Bad: span with onClick attribute has no tabindex -->
|
|
142
|
+
<span onclick="submitForm();" role="button">Submit</span>
|
|
143
|
+
<!-- Bad: anchor element without href is not focusable -->
|
|
144
|
+
<a onclick="showNextPage();" role="button">Next page</a>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Accessibility guidelines
|
|
148
|
+
|
|
149
|
+
- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
|
|
150
|
+
|
|
151
|
+
### Resources
|
|
152
|
+
|
|
153
|
+
- [Chrome Audit Rules, AX_FOCUS_02](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_02)
|
|
154
|
+
- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
|
|
155
|
+
- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
|
|
156
|
+
- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
|