Skip to content

Commit 72ed87a

Browse files
author
Ethan Cohen
committed
Allow alt prop to be empty string is role="presentation"
Fixes #6
1 parent 0a1aee3 commit 72ed87a

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

docs/rules/img-uses-alt.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ To tell this plugin to also check your `Image` element, specify this in your `.e
3535
```json
3636
{
3737
"rules": {
38-
"jsx-a11y/img-uses-alt": [ 2, "Image" ], // OR
38+
"jsx-a11y/img-uses-alt": [ 2, "Image" ], <!-- OR -->
3939
"jsx-a11y/img-uses-alt": [ 2, [ "Image", "Avatar" ] ]
4040
}
4141
}
@@ -49,6 +49,7 @@ Note that passing props as spread attribute without `alt` explicitly defined wil
4949
<img src="foo" alt={"Foo eating a sandwich."} />
5050
<img src="foo" alt={altText} />
5151
<img src="foo" alt={`${person} smiling`} />
52+
<img src="foo" alt="" role="presentation" /> <!-- Alt text can be an empty string if `role="presentation"` -->
5253
```
5354

5455
### Fail

src/rules/img-uses-alt.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,36 @@ module.exports = context => ({
2424

2525
const hasAltProp = hasAttribute(node.attributes, 'alt');
2626

27+
// Missing alt prop error.
2728
if (!hasAltProp) {
2829
context.report({
2930
node,
30-
message: `${nodeType} elements must have an alt prop`
31+
message: `${nodeType} elements must have an alt prop.`
3132
});
3233
return;
3334
}
3435

35-
const altProp = hasAltProp ? getAttributeValue(hasAltProp) : undefined;
36-
const isInvalid = hasAltProp === false || Boolean(altProp) === false;
36+
// Check if alt prop is undefined.
37+
const altProp = getAttributeValue(hasAltProp);
3738

38-
if (isInvalid) {
39+
// Check if alt prop is ""
40+
const emptyAlt = hasAltProp && hasAltProp.value
41+
&& hasAltProp.value.type === 'Literal'
42+
&& hasAltProp.value.value === "";
43+
44+
const hasRoleProp = hasAttribute(node.attributes, 'role');
45+
const roleProp = getAttributeValue(hasRoleProp);
46+
47+
// Allow altProp to be "" if `role="presentation"` is present.
48+
const isValid = altProp || (emptyAlt && hasRoleProp && roleProp.toUpperCase() === 'PRESENTATION');
49+
50+
// Undefined alt prop error.
51+
if (!isValid) {
3952
context.report({
4053
node,
41-
message: `${nodeType} alt prop must have a value`
54+
message: `${nodeType} alt prop must have a value. You can set alt="" if role="presentation" is applied.`
4255
});
56+
return;
4357
}
4458
}
4559
});

tests/src/rules/img-uses-alt.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ const parserOptions = {
2626
const ruleTester = new RuleTester();
2727

2828
const customMissingPropError = type => ({
29-
message: `${type} elements must have an alt prop`,
29+
message: `${type} elements must have an alt prop.`,
3030
type: 'JSXOpeningElement'
3131
});
3232

3333
const customAltValueError = type => ({
34-
message: `${type} alt prop must have a value`,
34+
message: `${type} alt prop must have a value. You can set alt="" if role="presentation" is applied.`,
3535
type: 'JSXOpeningElement'
3636
});
3737

@@ -65,6 +65,10 @@ ruleTester.run('img-uses-alt', rule, {
6565
{ code: '<img alt={foo.bar || ""} />', parserOptions },
6666
{ code: '<img alt={bar() || ""} />', parserOptions },
6767
{ code: '<img alt={foo.bar() || ""} />', parserOptions },
68+
{ code: '<img alt="" role="presentation" />', parserOptions }, // Allow alt to be undefined if role="presentation"
69+
{ code: '<img alt="" role={`presentation`} />', parserOptions },
70+
{ code: '<img alt="" role={"presentation"} />', parserOptions },
71+
{ code: '<img alt="this is lit..." role="presentation" />', parserOptions },
6872
{ code: '<img alt=" " />', parserOptions }, // For decorative images.
6973

7074
// CUSTOM ELEMENT TESTS FOR STRING OPTION
@@ -120,6 +124,9 @@ ruleTester.run('img-uses-alt', rule, {
120124
{ code: '<img alt={undefined} />;', errors: [ expectedAltValueError ], parserOptions },
121125
{ code: '<img alt={`${undefined}`} />;', errors: [ expectedAltValueError ], parserOptions },
122126
{ code: '<img alt="" />;', errors: [ expectedAltValueError ], parserOptions },
127+
{ code: '<img role="presentation" />;', errors: [ expectedMissingPropError ], parserOptions },
128+
{ code: '<img alt={undefined} role="presentation" />;', errors: [ expectedAltValueError ], parserOptions },
129+
{ code: '<img alt role="presentation" />;', errors: [ expectedAltValueError ], parserOptions },
123130
{ code: '<img src="xyz" />', errors: [ expectedMissingPropError ], parserOptions },
124131
{ code: '<img {...this.props} />', errors: [ expectedMissingPropError ], parserOptions },
125132
{ code: '<img alt={false || false} />', errors: [ expectedAltValueError ], parserOptions },

0 commit comments

Comments
 (0)