Skip to content

Commit

Permalink
Add rule S1077 (jsx-a11y/alt-text): Image, area, button with image …
Browse files Browse the repository at this point in the history
…and object elements should have an alternative text (#4391)
  • Loading branch information
ilia-kebets-sonarsource committed Nov 16, 2023
1 parent 6fbcb4e commit 86868b7
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 0 deletions.
11 changes: 11 additions & 0 deletions its/ruling/src/test/expected/jsts/Joust/typescript-S1077.json
@@ -0,0 +1,11 @@
{
"Joust:ts/components/game/Deck.tsx": [
33
],
"Joust:ts/components/game/Player.tsx": [
295
],
"Joust:ts/components/game/visuals/CardArt.tsx": [
97
]
}
18 changes: 18 additions & 0 deletions its/ruling/src/test/expected/jsts/console/typescript-S1077.json
@@ -0,0 +1,18 @@
{
"console:src/components/onboarding/OnboardingPopup/OnboardingPopup.tsx": [
55
],
"console:src/views/CLIAuthView/CLIAuthView/Left.tsx": [
37
],
"console:src/views/Integrations/Algolia/AlgoliaHeader.tsx": [
42
],
"console:src/views/ProjectRootView/OnboardSideNav.tsx": [
95
],
"console:src/views/models/AuthProviderPopup/AuthProviderPopup.tsx": [
134,
151
]
}
@@ -0,0 +1,5 @@
{
"courselit:packages/rich-text/src/Renderers/Media.js": [
12
]
}
72 changes: 72 additions & 0 deletions its/ruling/src/test/expected/jsts/desktop/typescript-S1077.json
@@ -0,0 +1,72 @@
{
"desktop:app/src/crash/crash-app.tsx": [
204
],
"desktop:app/src/ui/autocompletion/emoji-autocompletion-provider.tsx": [
93
],
"desktop:app/src/ui/branches/no-branches.tsx": [
22
],
"desktop:app/src/ui/branches/no-pull-requests.tsx": [
36
],
"desktop:app/src/ui/changes/multiple-selection.tsx": [
21
],
"desktop:app/src/ui/changes/no-changes.tsx": [
717
],
"desktop:app/src/ui/check-runs/ci-check-run-popover.tsx": [
245
],
"desktop:app/src/ui/check-runs/ci-check-run-rerun-dialog.tsx": [
223
],
"desktop:app/src/ui/diff/image-diffs/image-container.tsx": [
23
],
"desktop:app/src/ui/diff/index.tsx": [
174,
191
],
"desktop:app/src/ui/history/selected-commit.tsx": [
303,
428
],
"desktop:app/src/ui/no-repositories/no-repositories-view.tsx": [
142,
146
],
"desktop:app/src/ui/notifications/pull-request-checks-failed.tsx": [
224,
241
],
"desktop:app/src/ui/release-notes/release-notes-dialog.tsx": [
172,
180
],
"desktop:app/src/ui/repositories-list/repositories-list.tsx": [
255
],
"desktop:app/src/ui/thank-you/thank-you.tsx": [
64,
69
],
"desktop:app/src/ui/tutorial/done.tsx": [
42
],
"desktop:app/src/ui/tutorial/tutorial-panel.tsx": [
103
],
"desktop:app/src/ui/tutorial/welcome.tsx": [
28,
34,
41
],
"desktop:app/src/ui/welcome/welcome.tsx": [
206,
207,
215
]
}
5 changes: 5 additions & 0 deletions its/ruling/src/test/expected/jsts/redux/javascript-S1077.json
@@ -0,0 +1,5 @@
{
"redux:examples/real-world/components/User.js": [
11
]
}
@@ -0,0 +1,8 @@
{
"searchkit:docs/src/pages/index.js": [
42
],
"searchkit:examples/next/components/products.jsx": [
106
]
}
@@ -0,0 +1,36 @@
/**
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.javascript.checks;

import org.sonar.check.Rule;
import org.sonar.plugins.javascript.api.EslintBasedCheck;
import org.sonar.plugins.javascript.api.JavaScriptRule;
import org.sonar.plugins.javascript.api.TypeScriptRule;

@TypeScriptRule
@JavaScriptRule
@Rule(key = "S1077")
public class AltTextCheck implements EslintBasedCheck {

@Override
public String eslintKey() {
return "alt-text";
}
}
Expand Up @@ -59,6 +59,7 @@ public static List<Class<? extends JavaScriptCheck>> getAllChecks() {
AdjacentOverloadSignaturesCheck.class,
AlertUseCheck.class,
AlphabeticalSortCheck.class,
AltTextCheck.class,
AlwaysUseCurlyBracesCheck.class,
AnchorHasContentCheck.class,
AnchorIsValidCheck.class,
Expand Down
@@ -0,0 +1,90 @@
<h2>Why is this an issue?</h2>
<p>The <code>alt</code>, <code>aria-label</code> and <code>aria-labelledby</code> attributes provide a textual alternative to an image.</p>
<p>It is used whenever the actual image cannot be rendered.</p>
<p>Common reasons for that include:</p>
<ul>
<li> The image can no longer be found </li>
<li> Visually impaired users using a screen reader software </li>
<li> Image loading is disabled, to reduce data consumption on mobile phones </li>
</ul>
<p>It is also very important to not set an alternative text attribute to a non-informative value. For example <code>&lt;img ... alt="logo"&gt;</code>
is useless as it doesn’t give any information to the user. In this case, as for any other decorative image, it is better to use a CSS background image
instead of an <code>&lt;img&gt;</code> tag. If using CSS background-image is not possible, an empty <code>alt=""</code> is tolerated. See Exceptions
below.</p>
<p>This rule raises an issue when:</p>
<ul>
<li> An <code>&lt;img&gt;</code> element has no <code>alt</code> attribute. </li>
<li> An <code>&lt;input type="image"&gt;</code> element has no <code>alt</code>, <code>aria-label</code> or <code>aria-labelledby</code> attribute
or they hold an empty string. </li>
<li> An <code>&lt;area&gt;</code> element within an image map has no <code>alt</code>, <code>aria-label</code> or <code>aria-labelledby</code>
attribute. </li>
<li> An <code>&lt;object&gt;</code> element has no inner text, or <code>title</code>, <code>aria-label</code> or <code>aria-labelledby</code>
attribute </li>
</ul>
<h3>Noncompliant code example</h3>
<pre>
&lt;img src="foo.png" /&gt; &lt;!-- missing `alt` attribute --&gt;
&lt;input type="image" src="bar.png" /&gt; &lt;!-- missing alternative text attribute --&gt;
&lt;input type="image" src="bar.png" alt="" /&gt; &lt;!-- empty alternative text attribute on &lt;input&gt; --&gt;

&lt;img src="house.gif" usemap="#map1"
alt="rooms of the house." /&gt;
&lt;map id="map1" name="map1"&gt;
&lt;area shape="rect" coords="0,0,42,42"
href="bedroom.html"/&gt; &lt;!-- missing alternative text attribute on &lt;area&gt; --&gt;
&lt;area shape="rect" coords="0,0,21,21"
href="lounge.html" alt=""/&gt; &lt;!-- empty `alt` attribute on &lt;area&gt; --&gt;
&lt;/map&gt;

&lt;object {...props} /&gt; &lt;!-- missing alternative text attribute on &lt;area&gt; --&gt;
</pre>
<h3>Compliant solution</h3>
<pre>
&lt;img src="foo.png" alt="Some textual description of foo.png" /&gt;
&lt;input type="image" src="bar.png" aria-labelledby="Textual description of bar.png" /&gt;

&lt;img src="house.gif" usemap="#map1"
alt="rooms of the house." /&gt;
&lt;map id="map1" name="map1"&gt;
&lt;area shape="rect" coords="0,0,42,42"
href="bedroom.html" alt="Bedroom" /&gt;
&lt;area shape="rect" coords="0,0,21,21"
href="lounge.html" aria-label="Lounge"/&gt;
&lt;/map&gt;

&lt;object&gt;My welcoming Bar&lt;/object&gt;
</pre>
<h3>Exceptions</h3>
<p><code>&lt;img&gt;</code> elements with an empty string&nbsp;<code>alt=""</code> attribute won’t raise any issue. However, this way should be used
in two cases only:</p>
<p>When the image is decorative and it is not possible to use a CSS background image. For example, when the decorative <code>&lt;img&gt;</code> is
generated via javascript with a source image coming from a database, it is better to use an <code>&lt;img alt=""&gt;</code> tag rather than generate
CSS code.</p>
<pre>
&lt;li *ngFor="let image of images"&gt;
&lt;img [src]="image" alt=""&gt;
&lt;/li&gt;
</pre>
<p>When the image is not decorative but its <code>alt</code> text would repeat a nearby text. For example, images contained in links should not
duplicate the link’s text in their <code>alt</code> attribute, as it would make the screen reader repeat the text twice.</p>
<pre>
&lt;a href="flowers.html"&gt;
&lt;img src="tulip.gif" alt="" /&gt;
A blooming tulip
&lt;/a&gt;
</pre>
<p>In all other cases, you should use CSS background images.</p>
<p>See&nbsp;<a href="https://www.w3.org/WAI/tutorials/images/decision-tree/">W3C WAI&nbsp;Web Accessibility Tutorials</a> for more information.</p>
<h2>Resources</h2>
<ul>
<li> <a href="https://www.w3.org/TR/WCAG20-TECHS/H24.html">WCAG2, H24</a> - Providing text alternatives for the area elements of image maps </li>
<li> <a href="https://www.w3.org/TR/WCAG20-TECHS/H36.html">WCAG2, H36</a> - Using alt attributes on images used as submit buttons </li>
<li> <a href="https://www.w3.org/TR/WCAG20-TECHS/H37.html">WCAG2, H37</a> - Using alt attributes on img elements </li>
<li> <a href="https://www.w3.org/TR/WCAG20-TECHS/H67.html">WCAG2, H67</a> - Using null alt text and no title attribute on img elements for images
that AT should ignore </li>
<li> <a href="https://www.w3.org/TR/WCAG20-TECHS/H2.html">WCAG2, H2</a> - Combining adjacent image and text links for the same resource </li>
<li> <a href="https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0#qr-text-equiv-all">WCAG2, 1.1.1</a> - Non-text Content </li>
<li> <a href="https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0#qr-navigation-mechanisms-refs">WCAG2, 2.4.4</a> - Link Purpose (In Context) </li>
<li> <a href="https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0#qr-navigation-mechanisms-link">WCAG2, 2.4.9</a> - Link Purpose (Link Only) </li>
</ul>

@@ -0,0 +1,29 @@
{
"title": "Image, area, button with image and object elements should have an alternative text",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"accessibility",
"wcag2-a",
"react"
],
"defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-1077",
"sqKey": "S1077",
"scope": "All",
"quickfix": "infeasible",
"code": {
"impacts": {
"RELIABILITY": "LOW"
},
"attribute": "COMPLETE"
},
"compatibleLanguages": [
"JAVASCRIPT",
"TYPESCRIPT"
]
}
Expand Up @@ -11,6 +11,7 @@
"S905",
"S930",
"S1068",
"S1077",
"S1082",
"S1119",
"S1121",
Expand Down

0 comments on commit 86868b7

Please sign in to comment.