Skip to content

Commit df22065

Browse files
authored
Merge pull request #11 from microsoft/roxpal/image-link-missing-aria
Create rule for Image Link
2 parents a5bcea5 + bcf2f1f commit df22065

12 files changed

+245
-9
lines changed

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,17 @@ Any use of third-party trademarks or logos are subject to those third-party's po
4747
## Rules
4848
<!-- begin auto-generated rules list -->
4949

50-
| Name                                          | Description |
51-
| :----------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52-
| [icon-text-content-button-does-not-need-aria](docs/rules/icon-text-content-button-does-not-need-aria.md) | Accessibility: an image button with text content does not need aria labelling. The button already has an accessible name and the aria-label or aria-labelledby will override the text content for screen reader users. |
53-
| [image-button-missing-aria](docs/rules/image-button-missing-aria.md) | Accessibility: Image buttons must have accessible labelling: aria-label, aria-labelledby, aria-describedby |
54-
| [image-button-prefer-aria-over-title-attribute](docs/rules/image-button-prefer-aria-over-title-attribute.md) | Accessibility: prefer wai-aria over title or placeholder attributes. Title/placeholder can be used in addition to wai-aria. aria-label, aria-labelledby, aria-describedby |
55-
| [no-empty-buttons](docs/rules/no-empty-buttons.md) | Accessibility: buttons must either text content or accessible labelling |
56-
| [object-literal-button-no-missing-aria](docs/rules/object-literal-button-no-missing-aria.md) | Accessibility: Object literal image buttons must have accessible labelling: aria-label, aria-labelledby, aria-describedby |
57-
| [text-area-missing-label-v9](docs/rules/text-area-missing-label-v9.md) | Accessibility: Textarea must have an accessible name |
58-
| [text-content-button-does-not-need-aria](docs/rules/text-content-button-does-not-need-aria.md) | Accessibility: a button with text content does not need aria labelling. The button already has an accessible name and the aria-label will override the text content for screen reader users. |
50+
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
51+
52+
| Name                                          | Description | 🔧 |
53+
| :----------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- |
54+
| [icon-text-content-button-does-not-need-aria](docs/rules/icon-text-content-button-does-not-need-aria.md) | Accessibility: an image button with text content does not need aria labelling. The button already has an accessible name and the aria-label or aria-labelledby will override the text content for screen reader users. | |
55+
| [image-button-missing-aria](docs/rules/image-button-missing-aria.md) | Accessibility: Image buttons must have accessible labelling: aria-label, aria-labelledby, aria-describedby | |
56+
| [image-button-prefer-aria-over-title-attribute](docs/rules/image-button-prefer-aria-over-title-attribute.md) | Accessibility: prefer wai-aria over title or placeholder attributes. Title/placeholder can be used in addition to wai-aria. aria-label, aria-labelledby, aria-describedby | |
57+
| [image-link-missing-aria-v9](docs/rules/image-link-missing-aria-v9.md) | Accessibility: Image links must have an accessible name | 🔧 |
58+
| [no-empty-buttons](docs/rules/no-empty-buttons.md) | Accessibility: buttons must either text content or accessible labelling | |
59+
| [object-literal-button-no-missing-aria](docs/rules/object-literal-button-no-missing-aria.md) | Accessibility: Object literal image buttons must have accessible labelling: aria-label, aria-labelledby, aria-describedby | |
60+
| [text-area-missing-label-v9](docs/rules/text-area-missing-label-v9.md) | Accessibility: Textarea must have an accessible name | |
61+
| [text-content-button-does-not-need-aria](docs/rules/text-content-button-does-not-need-aria.md) | Accessibility: a button with text content does not need aria labelling. The button already has an accessible name and the aria-label will override the text content for screen reader users. | |
5962

6063
<!-- end auto-generated rules list -->

docs/rules/icon-text-content-button-does-not-need-aria.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
Accessibility: an image button with content prop does not need aria labelling. The button already has an accessible name and the aria-label or aria-labelledby will override the text content for screen reader users.
68
All interactive elements must have an accessible name.
79

docs/rules/image-button-missing-aria.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
7+
<!-- end auto-generated rule header -->
8+
59
All interactive elements must have an accessible name.
610

711
Image buttons without additional text content lack an accessible name.

docs/rules/image-button-prefer-aria-over-title-attribute.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
Image buttons must have accessible labelling: aria-label
68

79
<https://www.w3.org/TR/html-aria/>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Accessibility: Image links must have an accessible name (`@microsoft/fluentui-jsx-a11y/image-link-missing-aria-v9`)
2+
3+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
4+
5+
<!-- end auto-generated rule header -->
6+
7+
<!-- end auto-generated rule header -->
8+
9+
All interactive elements must have an accessible name.
10+
11+
Links that contain Images without additional text content lack an accessible name.
12+
13+
Ways to fix:
14+
15+
1) Add a title, aria-label or aria-labelledby attribute or text content to the Link tag.
16+
2) Add a title, aria-label or aria-labelledby attribute to the Image tag.
17+
18+
<https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/>
19+
20+
## Rule Details
21+
22+
This rule aims to make Image links accessible.
23+
24+
Examples of **incorrect** code for this rule:
25+
26+
```js
27+
28+
<Link href="#test"><Image src="/test.png"/></Link>
29+
<Link href="#test" title=""><Image src="/test.png"/></Link>
30+
<Link href="#test"><Image src="/test.png" title=""/></Link>
31+
32+
```
33+
34+
Examples of **correct** code for this rule:
35+
36+
```js
37+
38+
<Link href="#test"><Image src="/test.png"/>This is a label link</Link>
39+
<Link href="#test" title="This is a title for the link"><Image src="/test.png"/></Link>
40+
<Link href="#test"><Image src="/test.png" title="This is a title for the image link"/></Link>
41+
<Link href="#test"><Image src="/test.png" aria-label="This is an aria-label for the image link"/></Link>
42+
<Link href="#test"><Image src="/test.png" aria-labelledby="id1"/></Link>
43+
44+
```
45+
46+
## When Not To Use It
47+
48+
Give a short description of when it would be appropriate to turn off this rule.
49+
50+
## Further Reading
51+
52+
If there are other links that describe the issue this rule addresses, please include them here in a bulleted list.

docs/rules/no-empty-buttons.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
Buttons must either have text, content or accessible labelling
68

79
<https://www.w3.org/TR/html-aria/>

docs/rules/object-literal-button-no-missing-aria.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
A button with text content does not need aria labelling. The button already has an accessible name and the aria-label will override the text content for screen reader users.
68

79
<https://www.w3.org/TR/html-aria/>

docs/rules/text-area-missing-label-v9.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
## Rule Details
68

79
This rule aims to prevent that a text area is placed without a label.

docs/rules/text-content-button-does-not-need-aria.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<!-- end auto-generated rule header -->
44

5+
<!-- end auto-generated rule header -->
6+
57
Object literal image buttons must have accessible labelling: aria-label
68

79
<https://www.w3.org/TR/html-aria/>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
"use strict";
5+
6+
const { getPropValue, getProp, hasProp, elementType } = require('jsx-ast-utils');
7+
const { flattenChildren } = require('../util/flattenChildren');
8+
9+
//------------------------------------------------------------------------------
10+
// Rule Definition
11+
//------------------------------------------------------------------------------
12+
13+
/** @type {import('eslint').Rule.RuleModule} */
14+
module.exports = {
15+
meta: {
16+
type: "problem",
17+
docs: {
18+
description: "Accessibility: Image links must have an accessible name",
19+
recommended: true,
20+
url: "https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/", // URL to the documentation page for this rule
21+
},
22+
messages: {
23+
missingAriaLabel: "Accessibility Rule: Image links must have an accessible name. Link can have a title attribute or text content, or Image can have an aria-label, aria-labelledby, or title attribute."
24+
},
25+
fixable: "code",
26+
schema: [], // Add a schema if the rule has options
27+
},
28+
29+
create(context) {
30+
const hasNonEmptyProp = (attributes, name) => {
31+
return hasProp(attributes, name) && getPropValue(getProp(attributes, name)).trim().length > 0;
32+
};
33+
34+
//----------------------------------------------------------------------
35+
// Public
36+
//----------------------------------------------------------------------
37+
38+
return {
39+
// visitor functions for different types of nodes
40+
JSXOpeningElement(node) {
41+
if (elementType(node) === "Link") {
42+
const flatChildren = flattenChildren(node.parent);
43+
44+
// Check if there is text content
45+
const hasTextContent = flatChildren.some(child =>
46+
child.type === "JSXText"
47+
? child.value.trim().length > 0
48+
: false);
49+
50+
if (hasTextContent) return;
51+
52+
// Check if there is an accessible link
53+
const hasAccessibleLink = hasNonEmptyProp(node.attributes, "title")
54+
|| hasNonEmptyProp(node.attributes, "aria-label")
55+
|| hasNonEmptyProp(node.attributes, "aria-labelledby");
56+
57+
if (hasAccessibleLink) return;
58+
59+
// Check if there is an accessible image
60+
const hasAccessibleImage = flatChildren.some(child => {
61+
if (child.type === "JSXElement" && child.openingElement.name.name === "Image") {
62+
return hasProp(child.openingElement.attributes, "aria-hidden")
63+
? false
64+
: (hasNonEmptyProp(child.openingElement.attributes, "title")
65+
|| hasNonEmptyProp(child.openingElement.attributes, "aria-label")
66+
|| hasNonEmptyProp(child.openingElement.attributes, "aria-labelledby"));
67+
}
68+
return false;
69+
});
70+
71+
if (hasAccessibleImage) return;
72+
73+
// Report if there is no text content, accessible link or image
74+
if (!hasTextContent && !hasAccessibleLink && !hasAccessibleImage) {
75+
context.report({
76+
node,
77+
messageId: `missingAriaLabel`
78+
});
79+
}
80+
}
81+
}
82+
};
83+
},
84+
};

0 commit comments

Comments
 (0)