@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.
Files changed (229) hide show
  1. package/.babelrc +17 -0
  2. package/.eslintrc +44 -0
  3. package/CHANGELOG.md +774 -0
  4. package/LICENSE.md +8 -0
  5. package/README.md +423 -0
  6. package/__mocks__/IdentifierMock.js +15 -0
  7. package/__mocks__/JSXAttributeMock.js +39 -0
  8. package/__mocks__/JSXElementMock.js +37 -0
  9. package/__mocks__/JSXExpressionContainerMock.js +15 -0
  10. package/__mocks__/JSXSpreadAttributeMock.js +18 -0
  11. package/__mocks__/JSXTextMock.js +17 -0
  12. package/__mocks__/LiteralMock.js +17 -0
  13. package/__mocks__/genInteractives.js +218 -0
  14. package/__tests__/__util__/axeMapping.js +6 -0
  15. package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
  16. package/__tests__/__util__/helpers/parsers.js +186 -0
  17. package/__tests__/__util__/parserOptionsMapper.js +53 -0
  18. package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
  19. package/__tests__/index-test.js +40 -0
  20. package/__tests__/src/rules/accessible-emoji-test.js +66 -0
  21. package/__tests__/src/rules/alt-text-test.js +291 -0
  22. package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
  23. package/__tests__/src/rules/anchor-has-content-test.js +54 -0
  24. package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
  25. package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
  26. package/__tests__/src/rules/aria-props-test.js +69 -0
  27. package/__tests__/src/rules/aria-proptypes-test.js +311 -0
  28. package/__tests__/src/rules/aria-role-test.js +118 -0
  29. package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
  30. package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
  31. package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
  32. package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
  33. package/__tests__/src/rules/heading-has-content-test.js +85 -0
  34. package/__tests__/src/rules/html-has-lang-test.js +42 -0
  35. package/__tests__/src/rules/iframe-has-title-test.js +55 -0
  36. package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
  37. package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
  38. package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
  39. package/__tests__/src/rules/label-has-for-test.js +235 -0
  40. package/__tests__/src/rules/lang-test.js +59 -0
  41. package/__tests__/src/rules/media-has-caption-test.js +220 -0
  42. package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
  43. package/__tests__/src/rules/no-access-key-test.js +48 -0
  44. package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
  45. package/__tests__/src/rules/no-autofocus-test.js +68 -0
  46. package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
  47. package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
  48. package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
  49. package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
  50. package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
  51. package/__tests__/src/rules/no-onchange-test.js +57 -0
  52. package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
  53. package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
  54. package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
  55. package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
  56. package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
  57. package/__tests__/src/rules/scope-test.js +50 -0
  58. package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
  59. package/__tests__/src/util/attributesComparator-test.js +91 -0
  60. package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
  61. package/__tests__/src/util/getComputedRole-test.js +71 -0
  62. package/__tests__/src/util/getElementType-test.js +154 -0
  63. package/__tests__/src/util/getExplicitRole-test.js +35 -0
  64. package/__tests__/src/util/getImplicitRole-test.js +25 -0
  65. package/__tests__/src/util/getSuggestion-test.js +33 -0
  66. package/__tests__/src/util/getTabIndex-test.js +85 -0
  67. package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
  68. package/__tests__/src/util/implicitRoles/input-test.js +87 -0
  69. package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
  70. package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
  71. package/__tests__/src/util/isAbstractRole-test.js +51 -0
  72. package/__tests__/src/util/isContentEditable-test.js +52 -0
  73. package/__tests__/src/util/isDOMElement-test.js +30 -0
  74. package/__tests__/src/util/isDisabledElement-test.js +88 -0
  75. package/__tests__/src/util/isFocusable-test.js +111 -0
  76. package/__tests__/src/util/isInteractiveElement-test.js +104 -0
  77. package/__tests__/src/util/isInteractiveRole-test.js +59 -0
  78. package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
  79. package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
  80. package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
  81. package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
  82. package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
  83. package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
  84. package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
  85. package/__tests__/src/util/schemas-test.js +35 -0
  86. package/docs/rules/accessible-emoji.md +30 -0
  87. package/docs/rules/alt-text.md +168 -0
  88. package/docs/rules/anchor-ambiguous-text.md +91 -0
  89. package/docs/rules/anchor-has-content.md +64 -0
  90. package/docs/rules/anchor-is-valid.md +270 -0
  91. package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
  92. package/docs/rules/aria-props.md +29 -0
  93. package/docs/rules/aria-proptypes.md +30 -0
  94. package/docs/rules/aria-role.md +51 -0
  95. package/docs/rules/aria-unsupported-elements.md +30 -0
  96. package/docs/rules/autocomplete-valid.md +49 -0
  97. package/docs/rules/click-events-have-key-events.md +28 -0
  98. package/docs/rules/control-has-associated-label.md +113 -0
  99. package/docs/rules/heading-has-content.md +67 -0
  100. package/docs/rules/html-has-lang.md +31 -0
  101. package/docs/rules/iframe-has-title.md +37 -0
  102. package/docs/rules/img-redundant-alt.md +48 -0
  103. package/docs/rules/interactive-supports-focus.md +156 -0
  104. package/docs/rules/label-has-associated-control.md +152 -0
  105. package/docs/rules/label-has-for.md +130 -0
  106. package/docs/rules/lang.md +31 -0
  107. package/docs/rules/media-has-caption.md +48 -0
  108. package/docs/rules/mouse-events-have-key-events.md +58 -0
  109. package/docs/rules/no-access-key.md +30 -0
  110. package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
  111. package/docs/rules/no-autofocus.md +43 -0
  112. package/docs/rules/no-distracting-elements.md +41 -0
  113. package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
  114. package/docs/rules/no-noninteractive-element-interactions.md +145 -0
  115. package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
  116. package/docs/rules/no-noninteractive-tabindex.md +115 -0
  117. package/docs/rules/no-onchange.md +36 -0
  118. package/docs/rules/no-redundant-roles.md +46 -0
  119. package/docs/rules/no-static-element-interactions.md +114 -0
  120. package/docs/rules/prefer-tag-over-role.md +32 -0
  121. package/docs/rules/role-has-required-aria-props.md +31 -0
  122. package/docs/rules/role-supports-aria-props.md +39 -0
  123. package/docs/rules/scope.md +30 -0
  124. package/docs/rules/tabindex-no-positive.md +32 -0
  125. package/lib/configs/flat-config-base.js +11 -0
  126. package/lib/configs/legacy-config-base.js +9 -0
  127. package/lib/index.js +209 -0
  128. package/lib/rules/accessible-emoji.js +63 -0
  129. package/lib/rules/alt-text.js +218 -0
  130. package/lib/rules/anchor-ambiguous-text.js +64 -0
  131. package/lib/rules/anchor-has-content.js +60 -0
  132. package/lib/rules/anchor-is-valid.js +122 -0
  133. package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
  134. package/lib/rules/aria-props.js +59 -0
  135. package/lib/rules/aria-proptypes.js +114 -0
  136. package/lib/rules/aria-role.js +89 -0
  137. package/lib/rules/aria-unsupported-elements.js +64 -0
  138. package/lib/rules/autocomplete-valid.js +67 -0
  139. package/lib/rules/click-events-have-key-events.js +68 -0
  140. package/lib/rules/control-has-associated-label.js +103 -0
  141. package/lib/rules/heading-has-content.js +61 -0
  142. package/lib/rules/html-has-lang.js +50 -0
  143. package/lib/rules/iframe-has-title.js +50 -0
  144. package/lib/rules/img-redundant-alt.js +88 -0
  145. package/lib/rules/interactive-supports-focus.js +87 -0
  146. package/lib/rules/label-has-associated-control.js +127 -0
  147. package/lib/rules/label-has-for.js +150 -0
  148. package/lib/rules/lang.js +68 -0
  149. package/lib/rules/media-has-caption.js +96 -0
  150. package/lib/rules/mouse-events-have-key-events.js +94 -0
  151. package/lib/rules/no-access-key.js +43 -0
  152. package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
  153. package/lib/rules/no-autofocus.js +62 -0
  154. package/lib/rules/no-distracting-elements.js +54 -0
  155. package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
  156. package/lib/rules/no-noninteractive-element-interactions.js +95 -0
  157. package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
  158. package/lib/rules/no-noninteractive-tabindex.js +109 -0
  159. package/lib/rules/no-onchange.js +52 -0
  160. package/lib/rules/no-redundant-roles.js +86 -0
  161. package/lib/rules/no-static-element-interactions.js +102 -0
  162. package/lib/rules/prefer-tag-over-role.js +75 -0
  163. package/lib/rules/role-has-required-aria-props.js +88 -0
  164. package/lib/rules/role-supports-aria-props.js +78 -0
  165. package/lib/rules/scope.js +58 -0
  166. package/lib/rules/tabindex-no-positive.js +53 -0
  167. package/lib/util/attributesComparator.js +34 -0
  168. package/lib/util/getAccessibleChildText.js +55 -0
  169. package/lib/util/getComputedRole.js +19 -0
  170. package/lib/util/getElementType.js +30 -0
  171. package/lib/util/getExplicitRole.js +27 -0
  172. package/lib/util/getImplicitRole.js +24 -0
  173. package/lib/util/getSuggestion.js +32 -0
  174. package/lib/util/getTabIndex.js +34 -0
  175. package/lib/util/hasAccessibleChild.js +30 -0
  176. package/lib/util/implicitRoles/a.js +17 -0
  177. package/lib/util/implicitRoles/area.js +17 -0
  178. package/lib/util/implicitRoles/article.js +13 -0
  179. package/lib/util/implicitRoles/aside.js +13 -0
  180. package/lib/util/implicitRoles/body.js +13 -0
  181. package/lib/util/implicitRoles/button.js +13 -0
  182. package/lib/util/implicitRoles/datalist.js +13 -0
  183. package/lib/util/implicitRoles/details.js +13 -0
  184. package/lib/util/implicitRoles/dialog.js +13 -0
  185. package/lib/util/implicitRoles/form.js +13 -0
  186. package/lib/util/implicitRoles/h1.js +13 -0
  187. package/lib/util/implicitRoles/h2.js +13 -0
  188. package/lib/util/implicitRoles/h3.js +13 -0
  189. package/lib/util/implicitRoles/h4.js +13 -0
  190. package/lib/util/implicitRoles/h5.js +13 -0
  191. package/lib/util/implicitRoles/h6.js +13 -0
  192. package/lib/util/implicitRoles/hr.js +13 -0
  193. package/lib/util/implicitRoles/img.js +31 -0
  194. package/lib/util/implicitRoles/index.js +82 -0
  195. package/lib/util/implicitRoles/input.js +38 -0
  196. package/lib/util/implicitRoles/li.js +13 -0
  197. package/lib/util/implicitRoles/link.js +17 -0
  198. package/lib/util/implicitRoles/menu.js +19 -0
  199. package/lib/util/implicitRoles/menuitem.js +28 -0
  200. package/lib/util/implicitRoles/meter.js +13 -0
  201. package/lib/util/implicitRoles/nav.js +13 -0
  202. package/lib/util/implicitRoles/ol.js +13 -0
  203. package/lib/util/implicitRoles/option.js +13 -0
  204. package/lib/util/implicitRoles/output.js +13 -0
  205. package/lib/util/implicitRoles/progress.js +13 -0
  206. package/lib/util/implicitRoles/section.js +13 -0
  207. package/lib/util/implicitRoles/select.js +13 -0
  208. package/lib/util/implicitRoles/tbody.js +13 -0
  209. package/lib/util/implicitRoles/textarea.js +13 -0
  210. package/lib/util/implicitRoles/tfoot.js +13 -0
  211. package/lib/util/implicitRoles/thead.js +13 -0
  212. package/lib/util/implicitRoles/ul.js +13 -0
  213. package/lib/util/isAbstractRole.js +23 -0
  214. package/lib/util/isContentEditable.js +13 -0
  215. package/lib/util/isDOMElement.js +15 -0
  216. package/lib/util/isDisabledElement.js +23 -0
  217. package/lib/util/isFocusable.js +23 -0
  218. package/lib/util/isHiddenFromScreenReader.js +26 -0
  219. package/lib/util/isInteractiveElement.js +116 -0
  220. package/lib/util/isInteractiveRole.js +54 -0
  221. package/lib/util/isNonInteractiveElement.js +131 -0
  222. package/lib/util/isNonInteractiveRole.js +55 -0
  223. package/lib/util/isNonLiteralProperty.js +29 -0
  224. package/lib/util/isPresentationRole.js +13 -0
  225. package/lib/util/isSemanticRoleElement.js +54 -0
  226. package/lib/util/mayContainChildComponent.js +50 -0
  227. package/lib/util/mayHaveAccessibleLabel.js +95 -0
  228. package/lib/util/schemas.js +52 -0
  229. package/package.json +120 -0
@@ -0,0 +1,168 @@
1
+ # jsx-a11y/alt-text
2
+
3
+ 💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ Enforce that all elements that require alternative text have meaningful information to relay back to the end user. This is a critical component of accessibility for screen reader users in order for them to understand the content's purpose on the page. By default, this rule checks for alternative text on the following elements: `<img>`, `<area>`, `<input type="image">`, and `<object>`.
8
+
9
+ ## How to resolve
10
+
11
+ ### `<img>`
12
+
13
+ An `<img>` must have the `alt` prop set with meaningful text or as an empty string to indicate that it is an image for decoration.
14
+
15
+ For images that are being used as icons for a button or control, the `alt` prop should be set to an empty string (`alt=""`).
16
+
17
+ ```jsx
18
+ <button>
19
+ <img src="icon.png" alt="" />
20
+ Save
21
+
22
+ </button>
23
+ ```
24
+
25
+ The content of an `alt` attribute is used to calculate the accessible label of an element, whereas the text content is used to produce a label for the element. For this reason, adding a label to an icon can produce a confusing or duplicated label on a control that already has appropriate text content.
26
+
27
+ ### `<object>`
28
+
29
+ Add alternative text to all embedded `<object>` elements using either inner text, setting the `title` prop, or using the `aria-label` or `aria-labelledby` props.
30
+
31
+ ### `<input type="image">`
32
+
33
+ All `<input type="image">` elements must have a non-empty `alt` prop set with a meaningful description of the image or have the `aria-label` or `aria-labelledby` props set.
34
+
35
+ ### `<area>`
36
+
37
+ All clickable `<area>` elements within an image map have an `alt`, `aria-label` or `aria-labelledby` prop that describes the purpose of the link.
38
+
39
+ ## Rule options
40
+
41
+ This rule takes one optional object argument of type object:
42
+
43
+ ```json
44
+ {
45
+ "rules": {
46
+ "jsx-a11y/alt-text": [ 2, {
47
+ "elements": [ "img", "object", "area", "input[type=\"image\"]" ],
48
+ "img": ["Image"],
49
+ "object": ["Object"],
50
+ "area": ["Area"],
51
+ "input[type=\"image\"]": ["InputImage"]
52
+ }],
53
+ }
54
+ }
55
+ ```
56
+
57
+ The `elements` option is a whitelist for DOM elements to check for alternative text. If an element is removed from the default set of elements (noted above), any custom components for that component will also be ignored. In order to indicate any custom wrapper components that should be checked, you can map the DOM element to an array of JSX custom components. This is a good use case when you have a wrapper component that simply renders an `img` element, for instance (like in React):
58
+
59
+ ```jsx
60
+ // Image.js
61
+ const Image = props => {
62
+ const {
63
+ alt,
64
+ ...otherProps
65
+ } = props;
66
+
67
+ return (
68
+ <img alt={alt} {...otherProps} />
69
+ );
70
+ }
71
+
72
+ ...
73
+
74
+ // Header.js (for example)
75
+ ...
76
+ return (
77
+ <header>
78
+ <Image alt="Logo" src="logo.jpg" />
79
+ </header>
80
+
81
+ );
82
+ ```
83
+
84
+ Note that passing props as spread attribute without explicitly the necessary accessibility props defined will cause this rule to fail. Explicitly pass down the set of props needed for rule to pass. Use `Image` component above as a reference for destructuring and applying the prop. **It is a good thing to explicitly pass props that you expect to be passed for self-documentation.** For example:
85
+
86
+ #### Bad
87
+
88
+ ```jsx
89
+ function Foo(props) {
90
+ return <img {...props} />
91
+ }
92
+ ```
93
+
94
+ #### Good
95
+
96
+ ```jsx
97
+ function Foo({ alt, ...props}) {
98
+ return <img alt={alt} {...props} />
99
+ }
100
+
101
+ // OR
102
+
103
+ function Foo(props) {
104
+ const {
105
+ alt,
106
+
107
+ ...otherProps
108
+ } = props;
109
+
110
+ return <img alt={alt} {...otherProps} />
111
+ }
112
+ ```
113
+
114
+ ### Succeed
115
+
116
+ ```jsx
117
+ <img src="foo" alt="Foo eating a sandwich." />
118
+ <img src="foo" alt={"Foo eating a sandwich."} />
119
+ <img src="foo" alt={altText} />
120
+ <img src="foo" alt={`${person} smiling`} />
121
+ <img src="foo" alt="" />
122
+
123
+ <object aria-label="foo" />
124
+ <object aria-labelledby="id1" />
125
+ <object>Meaningful description</object>
126
+ <object title="An object" />
127
+
128
+ <area aria-label="foo" />
129
+ <area aria-labelledby="id1" />
130
+
131
+ <area alt="This is descriptive!" />
132
+
133
+ <input type="image" alt="This is descriptive!" />
134
+ <input type="image" aria-label="foo" />
135
+ <input type="image" aria-labelledby="id1" />
136
+
137
+ ```
138
+
139
+ ### Fail
140
+
141
+ ```jsx
142
+ <img src="foo" />
143
+ <img {...props} />
144
+ <img {...props} alt /> // Has no value
145
+ <img {...props} alt={undefined} /> // Has no value
146
+ <img {...props} alt={`${undefined}`} /> // Has no value
147
+ <img src="foo" role="presentation" /> // Avoid ARIA if it can be achieved without
148
+
149
+ <img src="foo" role="none" /> // Avoid ARIA if it can be achieved without
150
+
151
+ <object {...props} />
152
+
153
+
154
+ <area {...props} />
155
+
156
+ <input type="image" {...props} />
157
+ ```
158
+
159
+ ## Accessibility guidelines
160
+
161
+ - [WCAG 1.1.1](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html)
162
+
163
+ ### Resources
164
+
165
+ - [axe-core, object-alt](https://dequeuniversity.com/rules/axe/3.2/object-alt)
166
+ - [axe-core, image-alt](https://dequeuniversity.com/rules/axe/3.2/image-alt)
167
+ - [axe-core, input-image-alt](https://dequeuniversity.com/rules/axe/3.2/input-image-alt)
168
+ - [axe-core, area-alt](https://dequeuniversity.com/rules/axe/3.2/area-alt)
@@ -0,0 +1,91 @@
1
+ # jsx-a11y/anchor-ambiguous-text
2
+
3
+ 🚫 This rule is _disabled_ in the ☑️ `recommended` config.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ Enforces `<a>` values are not exact matches for the phrases "click here", "here", "link", "a link", or "learn more". Screen readers announce tags as links/interactive, but rely on values for context. Ambiguous anchor descriptions do not provide sufficient context for users.
8
+
9
+ ## Rule options
10
+
11
+ This rule takes one optional object argument with the parameter `words`.
12
+
13
+ ```json
14
+ {
15
+ "rules": {
16
+ "jsx-a11y/anchor-ambiguous-text": [2, {
17
+ "words": ["click this"],
18
+ }],
19
+ }
20
+ }
21
+ ```
22
+
23
+ The `words` option allows users to modify the strings that can be checked for in the anchor text. Useful for specifying other words in other languages. The default value is set by `DEFAULT_AMBIGUOUS_WORDS`:
24
+
25
+ ```js
26
+ const DEFAULT_AMBIGUOUS_WORDS = ['click here', 'here', 'link', 'a link', 'learn more'];
27
+ ```
28
+
29
+ The logic to calculate the inner text of an anchor is as follows:
30
+
31
+ - if an element has the `aria-label` property, its value is used instead of the inner text
32
+ - if an element has `aria-hidden="true`, it is skipped over
33
+ - if an element is `<img />` or configured to be interpreted like one, its `alt` value is used as its inner text
34
+
35
+ Note that this rule still disallows ambiguous `aria-label` or `alt` values.
36
+
37
+ Note that this rule is case-insensitive, trims whitespace, and ignores certain punctuation (`[,.?¿!‽¡;:]`). It only looks for **exact matches**.
38
+
39
+ ### Succeed
40
+
41
+ ```jsx
42
+ <a>read this tutorial</a> // passes since it is not one of the disallowed words
43
+ <a>${here}</a> // this is valid since 'here' is a variable name
44
+ <a aria-label="tutorial on using eslint-plugin-jsx-a11y">click here</a> // the aria-label supersedes the inner text
45
+ ```
46
+
47
+ ### Fail
48
+
49
+ ```jsx
50
+ <a>here</a>
51
+ <a>HERE</a>
52
+ <a>link</a>
53
+ <a>click here</a>
54
+ <a>learn more</a>
55
+ <a>learn more.</a>
56
+ <a>learn more,</a>
57
+ <a>learn more?</a>
58
+ <a>learn more!</a>
59
+ <a>learn more:</a>
60
+ <a>learn more;</a>
61
+ <a>a link</a>
62
+ <a> a link </a>
63
+ <a><span> click </span> here</a> // goes through element children
64
+ <a>a<i></i> link</a>
65
+ <a><i></i>a link</a>
66
+ <a><span aria-hidden="true">more text</span>learn more</a> // skips over elements with aria-hidden=true
67
+ <a aria-label="click here">something</a> // the aria-label here is inaccessible
68
+ <a><img alt="click here"/></a> // the alt tag is still ambiguous
69
+ <a alt="tutorial on using eslint-plugin-jsx-a11y">click here</a> // the alt tag is only parsed on img
70
+ ```
71
+
72
+ ## Accessibility guidelines
73
+
74
+ Ensure anchor tags describe the content of the link, opposed to simply describing them as a link.
75
+
76
+ Compare
77
+
78
+ ```jsx
79
+ <p><a href="#">click here</a> to read a tutorial by Foo Bar</p>
80
+ ```
81
+
82
+ which can be more concise and accessible with
83
+
84
+ ```jsx
85
+ <p>read <a href="#">a tutorial by Foo Bar</a></p>
86
+ ```
87
+
88
+ ### Resources
89
+
90
+ 1. [WebAIM, Hyperlinks](https://webaim.org/techniques/hypertext/)
91
+ 2. [Deque University, Link Checklist - 'Avoid "link" (or similar) in the link text'](https://dequeuniversity.com/checklists/web/links)
@@ -0,0 +1,64 @@
1
+ # jsx-a11y/anchor-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 anchors 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
+ Alternatively, you may use the `title` prop or the `aria-label` prop.
10
+
11
+ ## Rule options
12
+
13
+ This rule takes one optional object argument of type object:
14
+
15
+ ```json
16
+ {
17
+ "rules": {
18
+ "jsx-a11y/anchor-has-content": [ 2, {
19
+ "components": [ "Anchor" ],
20
+ }],
21
+ }
22
+ }
23
+ ```
24
+
25
+ For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `a` element (like in React):
26
+
27
+ ```js
28
+ // Anchor.js
29
+ const Anchor = props => {
30
+ return (
31
+ <a {...props}>{ props.children }</a>
32
+ );
33
+ }
34
+
35
+ ...
36
+
37
+ // CreateAccount.js (for example)
38
+ ...
39
+ return (
40
+ <Anchor>Create Account</Anchor>
41
+ );
42
+ ```
43
+
44
+
45
+ ### Succeed
46
+ ```jsx
47
+ <a>Anchor Content!</a>
48
+ <a><TextWrapper /></a>
49
+ <a dangerouslySetInnerHTML={{ __html: 'foo' }} />
50
+ <a title='foo' />
51
+ <a aria-label='foo' />
52
+ ```
53
+
54
+ ### Fail
55
+ ```jsx
56
+ <a />
57
+ <a><TextWrapper aria-hidden /></a>
58
+ ```
59
+ ## Accessibility guidelines
60
+ - [WCAG 2.4.4](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context)
61
+ - [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
62
+
63
+ ### Resources
64
+ - [axe-core, link-name](https://dequeuniversity.com/rules/axe/3.2/link-name)
@@ -0,0 +1,270 @@
1
+ # jsx-a11y/anchor-is-valid
2
+
3
+ 💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ The HTML `<a>` element, with a valid `href` attribute, is formally defined as representing a **hyperlink**. That is, a link between one HTML document and another, or between one location inside an HTML document and another location inside the same document.
8
+
9
+ In fact, the interactive, underlined `<a>` element has become so synonymous with web navigation that this expectation has become entrenched inside browsers, assistive technologies such as screen readers and in how people generally expect the internet to behave. In short, anchors should navigate.
10
+
11
+ The use of JavaScript frameworks and libraries, like _React_, has made it very easy to add or subtract functionality from the standard HTML elements. This has led to _anchors_ often being used in applications based on how they look and function instead of what they represent.
12
+
13
+ Whilst it is possible, for example, to turn the `<a>` element into a fully functional `<button>` element with ARIA, the native user agent implementations of HTML elements are to be preferred over custom ARIA solutions.
14
+
15
+ ## How do I resolve this error?
16
+
17
+ ### Case: I want to perform an action and need a clickable UI element
18
+
19
+ The native user agent implementations of the `<a>` and `<button>` elements not only differ in how they look and how they act when activated, but also in how the user is expected to interact with them. Both are perfectly clickable when using a mouse, but keyboard users expect `<a>` to activate on `enter` only and `<button>` to activate on _both_ `enter` and `space`.
20
+
21
+ This is exacerbated by the expectation sighted users have of how _buttons_ and _anchors_ work based on their appearance. Therefore we find that using _anchors_ as _buttons_ can easily create confusion without a relatively complicated ARIA and CSS implementation that only serves to create an element HTML already offers and browsers already implement fully accessibly.
22
+
23
+ We are aware that sometimes _anchors_ are used instead of _buttons_ to achieve a specific visual design. When using the `<button>` element this can still be achieved with styling but, due to the meaning many people attach to the standard underlined `<a>` due its appearance, please reconsider this in the design.
24
+
25
+ Consider the following:
26
+
27
+ ```jsx
28
+ <a href="javascript:void(0)" onClick={foo}>Perform action</a>
29
+ <a href="#" onClick={foo}>Perform action</a>
30
+ <a onClick={foo}>Perform action</a>
31
+ ```
32
+
33
+ All these _anchor_ implementations indicate that the element is only used to execute JavaScript code. All the above should be replaced with:
34
+
35
+ ```jsx
36
+ <button onClick={foo}>Perform action</button>
37
+ ```
38
+
39
+ ### Case: I want navigable links
40
+
41
+ An `<a>` element without an `href` attribute no longer functions as a hyperlink. That means that it can no longer accept keyboard focus or be clicked on. The documentation for [no-noninteractive-tabindex](no-noninteractive-tabindex.md) explores this further. Preferably use another element (such as `div` or `span`) for display of text.
42
+
43
+ To properly function as a hyperlink, the `href` attribute should be present and also contain a valid _URL_. _JavaScript_ strings, empty values or using only **#** are not considered valid `href` values.
44
+
45
+ Valid `href` attributes values are:
46
+
47
+ ```jsx
48
+ <a href="/some/valid/uri">Navigate to page</a>
49
+ <a href="/some/valid/uri#top">Navigate to page and location</a>
50
+ <a href="#top">Navigate to internal page location</a>
51
+ ```
52
+
53
+ ### Case: I need the HTML to be interactive, don't I need to use an a tag for that?
54
+
55
+ An `<a>` tag is not inherently interactive. Without an href attribute, it really is no different from a `<span>`.
56
+
57
+ Let's look at an example that is not accessible by all users:
58
+
59
+ ```jsx
60
+ <a
61
+ className="thing"
62
+ onMouseEnter={() => this.setState({ showSomething: true })}
63
+ >
64
+ {label}
65
+ </a>
66
+ ```
67
+
68
+ If you need to create an interface element that the user can click on, consider using a button:
69
+
70
+ ```jsx
71
+ <button
72
+ className="thing"
73
+ onClick={() => this.setState({ showSomething: true })}
74
+ >
75
+ {label}
76
+ </button>
77
+ ```
78
+
79
+ If you want to navigate while providing the user with extra functionality, for example in the `onMouseEnter` event, use an anchor with an `href` attribute containing a URL or path as its value.
80
+
81
+ ```jsx
82
+ <a
83
+ href={someValidPath}
84
+ className="thing"
85
+ onMouseEnter={() => this.setState({ showSomething: true })}
86
+ >
87
+ {label}
88
+ </a>
89
+ ```
90
+
91
+ If you need to create an interface element that the user can mouse over or mouse out of, consider using a div element. In this case, you may need to apply a role of presentation or an interactive role. Interactive ARIA roles include `button`, `link`, `checkbox`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `radio`, `searchbox`, `switch` and `textbox`.
92
+
93
+ ```jsx
94
+ <div
95
+ role="menuitem"
96
+ className="thing"
97
+ onClick={() => this.setState({ showSomething: true })}
98
+ onMouseEnter={() => this.setState({ showSomething: true })}
99
+ >
100
+ {label}
101
+ </div>
102
+ ```
103
+
104
+ In the example immediately above an `onClick` event handler was added to provide the same experience mouse users enjoy to keyboard-only and touch-screen users. Never fully rely on mouse events alone to expose functionality.
105
+
106
+ ### Case: I use Next.js and I'm getting this error inside of `<Link>`s
107
+
108
+ This is a [known issue](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/402) with Next.js's decision to construct internal links by nesting an href-free `<a>` tag inside of a `<Link>` component. Next.js is also [aware of the issue](https://github.com/vercel/next.js/issues/5533) and has an [RFC](https://github.com/vercel/next.js/discussions/8207) working towards a solution.
109
+
110
+ Until the Next.js API can be updated to a more performant and standard setup, you have a few workaround options:
111
+
112
+ 1. If you have only a few `Link`s, or they're clustered in just a few files like `nav.tsx`, you can use disable macros like `{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}` to turn off validation of this rule for those usages.
113
+
114
+ 2. You can use the `Link` component's `passHref` prop to override a dummy `href` on the `<a>`:
115
+ ```typescript
116
+ <Link href="/my-amazing-page" passHref>
117
+ <a href="replace">Go to my amazing page</a>
118
+ </Link>
119
+ ```
120
+
121
+ 3. You can invest in a custom component that wraps the creation of the `Link` and `a`. You can then add your new custom component to the list of components to validate to ensure that your links are all created with a navigable href. A sample custom component is shared [here](https://gist.github.com/zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b) and it would be used like this:
122
+ ```typescript
123
+ // Internally, LinkTo handles the making of the Link and A, collecting the
124
+ // need for a lint workaround into a single file.
125
+ // Externally, LinkTo can be linted using this rule, ensuring it will always
126
+ // have a valid href prop.
127
+ <LinkTo href="/my-amazing-page">Go to my amazing page</LinkTo>
128
+ ```
129
+
130
+ ### Case: I understand the previous cases but still need an element resembling a link that is purely clickable
131
+
132
+ We recommend, without reserve, that elements resembling anchors should navigate. This will provide a superior user experience to a larger group of users out there.
133
+
134
+ However, we understand that developers are not always in total control of the visual design of web applications. In cases where it is imperative to provide an element resembling an anchor that purely acts as a click target with no navigation as result, we would like to recommend a compromise.
135
+
136
+ Again change the element to a `<button>`:
137
+
138
+ ```jsx
139
+ <button
140
+ type="button"
141
+ className="link-button"
142
+ onClick={() => this.setState({ showSomething: true })}
143
+ >
144
+ Press me, I look like a link
145
+ </button>
146
+ ```
147
+
148
+ Then use styling to change its appearance to that of a link:
149
+
150
+ ```css
151
+ .link-button {
152
+ background-color: transparent;
153
+ border: none;
154
+ cursor: pointer;
155
+ text-decoration: underline;
156
+ display: inline;
157
+ margin: 0;
158
+ padding: 0;
159
+ }
160
+ ```
161
+
162
+ This button element can now also be used inline in text.
163
+
164
+ Once again we stress that this is an inferior implementation and some users will encounter difficulty to use your website, however, it will allow a larger group of people to interact with your website than the alternative of ignoring the rule's warning.
165
+
166
+ ## Rule options
167
+
168
+ This rule takes one optional object argument of type object:
169
+
170
+ ```json
171
+ {
172
+ "rules": {
173
+ "jsx-a11y/anchor-is-valid": [
174
+ "error",
175
+ {
176
+ "components": ["Link"],
177
+ "specialLink": ["hrefLeft", "hrefRight"],
178
+ "aspects": ["noHref", "invalidHref", "preferButton"]
179
+ }
180
+ ]
181
+ }
182
+ }
183
+ ```
184
+
185
+ For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for the props designated in the `specialLink` options (**always including** `href`). This is a good use case when you have a wrapper component that simply renders an `<a>` element (like in React):
186
+
187
+ ```js
188
+ // Link.js
189
+ const Link = props => <a {...props}>A link</a>;
190
+
191
+ ...
192
+
193
+ // NavBar.js (for example)
194
+ ...
195
+ return (
196
+ <nav>
197
+ <Link href="/home" />
198
+ </nav>
199
+ );
200
+ ```
201
+
202
+ For the `aspects` option, these strings determine which sub-rules are run. This allows omission of certain error types in restrictive environments.
203
+
204
+ - `noHref`: Checks whether an anchor contains an `href` attribute.
205
+ - `invalidHref`: Checks if a given `href` value is valid.
206
+ - `preferButton`: Checks if anchors have been used as buttons.
207
+
208
+ The option can be used on its own or with the `components` and `specialLink` options.
209
+
210
+ If omitted, all sub-rule aspects will be run by default. This is the recommended configuration for all cases except where the rule becomes unusable due to well founded restrictions.
211
+
212
+ The option must contain at least one `aspect`.
213
+
214
+ ### Succeed
215
+
216
+ ```jsx
217
+ <a href="https://github.com" />
218
+ <a href="#section" />
219
+ <a href="foo" />
220
+ <a href="/foo/bar" />
221
+ <a href={someValidPath} />
222
+ <a href="https://github.com" onClick={foo} />
223
+ <a href="#section" onClick={foo} />
224
+ <a href="foo" onClick={foo} />
225
+ <a href="/foo/bar" onClick={foo} />
226
+ <a href={someValidPath} onClick={foo} />
227
+ ```
228
+
229
+ ### Fail
230
+
231
+ Anchors should be a button:
232
+
233
+ ```jsx
234
+ <a onClick={foo} />
235
+ <a href="#" onClick={foo} />
236
+ <a href={"#"} onClick={foo} />
237
+ <a href={`#`} onClick={foo} />
238
+ <a href="javascript:void(0)" onClick={foo} />
239
+ <a href={"javascript:void(0)"} onClick={foo} />
240
+ <a href={`javascript:void(0)`} onClick={foo} />
241
+ ```
242
+
243
+ Missing `href` attribute:
244
+
245
+ ```jsx
246
+ <a />
247
+ <a href={undefined} />
248
+ <a href={null} />
249
+ ```
250
+
251
+ Invalid `href` attribute:
252
+
253
+ ```jsx
254
+ <a href="#" />
255
+ <a href={"#"} />
256
+ <a href={`#`} />
257
+ <a href="javascript:void(0)" />
258
+ <a href={"javascript:void(0)"} />
259
+ <a href={`javascript:void(0)`} />
260
+ ```
261
+
262
+ ## Accessibility guidelines
263
+
264
+ - [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
265
+
266
+ ### Resources
267
+
268
+ - [WebAIM - Introduction to Links and Hypertext](https://webaim.org/techniques/hypertext/)
269
+ - [Links vs. Buttons in Modern Web Applications](https://marcysutton.com/links-vs-buttons-in-modern-web-applications/)
270
+ - [Using ARIA - Notes on ARIA use in HTML](https://www.w3.org/TR/using-aria/#NOTES)
@@ -0,0 +1,52 @@
1
+ # jsx-a11y/aria-activedescendant-has-tabindex
2
+
3
+ 💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ `aria-activedescendant` is used to manage focus within a [composite widget](https://www.w3.org/TR/wai-aria/#composite).
8
+ The element with the attribute `aria-activedescendant` retains the active document
9
+ focus; it indicates which of its child elements has secondary focus by assigning
10
+ the ID of that element to the value of `aria-activedescendant`. This pattern is
11
+ used to build a widget like a search typeahead select list. The search input box
12
+ retains document focus so that the user can type in the input. If the down arrow
13
+ key is pressed and a search suggestion is highlighted, the ID of the suggestion
14
+ element will be applied as the value of `aria-activedescendant` on the input
15
+ element.
16
+
17
+ Because an element with `aria-activedescendant` must be tabbable, it must either
18
+ have an inherent `tabIndex` of zero or declare a `tabIndex` attribute.
19
+
20
+ ## Rule details
21
+
22
+ This rule takes no arguments.
23
+
24
+ ### Succeed
25
+ ```jsx
26
+ <CustomComponent />
27
+ <CustomComponent aria-activedescendant={someID} />
28
+ <CustomComponent aria-activedescendant={someID} tabIndex={0} />
29
+ <CustomComponent aria-activedescendant={someID} tabIndex={-1} />
30
+ <div />
31
+ <input />
32
+ <div tabIndex={0} />
33
+ <div aria-activedescendant={someID} tabIndex={0} />
34
+ <div aria-activedescendant={someID} tabIndex="0" />
35
+ <div aria-activedescendant={someID} tabIndex={1} />
36
+ <div aria-activedescendant={someID} tabIndex={-1} />
37
+ <div aria-activedescendant={someID} tabIndex="-1" />
38
+ <input aria-activedescendant={someID} />
39
+ <input aria-activedescendant={someID} tabIndex={0} />
40
+ <input aria-activedescendant={someID} tabIndex={-1} />
41
+ ```
42
+
43
+ ### Fail
44
+ ```jsx
45
+ <div aria-activedescendant={someID} />
46
+ ```
47
+
48
+ ## Accessibility guidelines
49
+ General best practice (reference resources)
50
+
51
+ ### Resources
52
+ - [MDN, Using the aria-activedescendant attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-activedescendant_attribute)
@@ -0,0 +1,29 @@
1
+ # jsx-a11y/aria-props
2
+
3
+ 💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ Elements cannot use an invalid ARIA attribute. This will fail if it finds an `aria-*` property that is not listed in [WAI-ARIA States and Properties spec](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties).
8
+
9
+ ## Rule details
10
+
11
+ This rule takes no arguments.
12
+
13
+ ### Succeed
14
+ ```jsx
15
+ <!-- Good: Labeled using correctly spelled aria-labelledby -->
16
+ <div id="address_label">Enter your address</div>
17
+ <input aria-labelledby="address_label">
18
+ ```
19
+
20
+ ### Fail
21
+
22
+ ```jsx
23
+ <!-- Bad: Labeled using incorrectly spelled aria-labeledby -->
24
+ <div id="address_label">Enter your address</div>
25
+ <input aria-labeledby="address_label">
26
+ ```
27
+
28
+ ## Accessibility guidelines
29
+ - [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)