Skip to content

Commit 09254b3

Browse files
authored
[new] - Add iframe-has-title rule. (#137)
* [new] - Add frame-has-title rule. * Fix comment. * Change frame to just check iframe. * Add better documentation and edge cases for bad title values. * Enforce that the title is a string value.
1 parent d9743bf commit 09254b3

File tree

5 files changed

+125
-0
lines changed

5 files changed

+125
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ You can also enable all the recommended rules at once. Add `plugin:jsx-a11y/reco
9191
- [heading-has-content](docs/rules/heading-has-content.md): Enforce heading (`h1`, `h2`, etc) elements contain accessible content.
9292
- [href-no-hash](docs/rules/href-no-hash.md): Enforce an anchor element's `href` prop value is not just `#`.
9393
- [html-has-lang](docs/rules/html-has-lang.md): Enforce `<html>` element has `lang` prop.
94+
- [iframe-has-title](docs/rules/iframe-has-title.md): Enforce iframe elements have a title attribute.
9495
- [img-has-alt](docs/rules/img-has-alt.md): Enforce that `<img>` JSX elements use the `alt` prop.
9596
- [img-redundant-alt](docs/rules/img-redundant-alt.md): Enforce `<img>` alt prop does not contain the word "image", "picture", or "photo".
9697
- [label-has-for](docs/rules/label-has-for.md): Enforce that `<label>` elements have the `htmlFor` prop.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* @fileoverview Enforce iframe elements have a title attribute.
3+
* @author Ethan Cohen
4+
*/
5+
6+
// -----------------------------------------------------------------------------
7+
// Requirements
8+
// -----------------------------------------------------------------------------
9+
10+
import { RuleTester } from 'eslint';
11+
import rule from '../../../src/rules/iframe-has-title';
12+
13+
const parserOptions = {
14+
ecmaVersion: 6,
15+
ecmaFeatures: {
16+
jsx: true,
17+
},
18+
};
19+
20+
// -----------------------------------------------------------------------------
21+
// Tests
22+
// -----------------------------------------------------------------------------
23+
24+
const ruleTester = new RuleTester();
25+
26+
const expectedError = {
27+
message: '<iframe> elements must have a unique title property.',
28+
type: 'JSXOpeningElement',
29+
};
30+
31+
ruleTester.run('html-has-lang', rule, {
32+
valid: [
33+
{ code: '<div />;', parserOptions },
34+
{ code: '<iframe title="Unique title" />', parserOptions },
35+
{ code: '<iframe title={foo} />', parserOptions },
36+
{ code: '<FooComponent />', parserOptions },
37+
],
38+
invalid: [
39+
{ code: '<iframe />', errors: [expectedError], parserOptions },
40+
{ code: '<iframe {...props} />', errors: [expectedError], parserOptions },
41+
{ code: '<iframe title={undefined} />', errors: [expectedError], parserOptions },
42+
{ code: '<iframe title="" />', errors: [expectedError], parserOptions },
43+
{ code: '<iframe title={false} />', errors: [expectedError], parserOptions },
44+
{ code: '<iframe title={true} />', errors: [expectedError], parserOptions },
45+
{ code: "<iframe title={''} />", errors: [expectedError], parserOptions },
46+
{ code: '<iframe title={``} />', errors: [expectedError], parserOptions },
47+
{ code: '<iframe title={""} />', errors: [expectedError], parserOptions },
48+
{ code: '<iframe title={42} />', errors: [expectedError], parserOptions },
49+
],
50+
});

docs/rules/iframe-has-title.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# iframe-has-title
2+
3+
`<iframe>` elements must have a unique title property to indicate its content to the user.
4+
5+
#### References
6+
1. [Deque University](https://dequeuniversity.com/rules/axe/1.1/frame-title)
7+
8+
## Rule details
9+
10+
This rule takes no arguments.
11+
12+
### Succeed
13+
```jsx
14+
<iframe title="This is a unique title" />
15+
<iframe title={uniqueTitle} />
16+
```
17+
18+
### Fail
19+
```jsx
20+
<iframe />
21+
<iframe {...props} />
22+
<iframe title="" />
23+
<iframe title={''} />
24+
<iframe title={``} />
25+
<iframe title={undefined} />
26+
<iframe title={false} />
27+
<iframe title={true} />
28+
<iframe title={42} />
29+
```

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = {
1111
'heading-has-content': require('./rules/heading-has-content'),
1212
'href-no-hash': require('./rules/href-no-hash'),
1313
'html-has-lang': require('./rules/html-has-lang'),
14+
'iframe-has-title': require('./rules/iframe-has-title'),
1415
'img-has-alt': require('./rules/img-has-alt'),
1516
'img-redundant-alt': require('./rules/img-redundant-alt'),
1617
'label-has-for': require('./rules/label-has-for'),
@@ -44,6 +45,7 @@ module.exports = {
4445
'jsx-a11y/heading-has-content': 'error',
4546
'jsx-a11y/href-no-hash': 'error',
4647
'jsx-a11y/html-has-lang': 'error',
48+
'jsx-a11y/iframe-has-title': 'error',
4749
'jsx-a11y/img-has-alt': 'error',
4850
'jsx-a11y/img-redundant-alt': 'error',
4951
'jsx-a11y/label-has-for': 'error',

src/rules/iframe-has-title.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @fileoverview Enforce iframe elements have a title attribute.
3+
* @author Ethan Cohen
4+
*/
5+
6+
// ----------------------------------------------------------------------------
7+
// Rule Definition
8+
// ----------------------------------------------------------------------------
9+
10+
import { elementType, getProp, getPropValue } from 'jsx-ast-utils';
11+
import { generateObjSchema } from '../util/schemas';
12+
13+
const errorMessage = '<iframe> elements must have a unique title property.';
14+
15+
const schema = generateObjSchema();
16+
17+
module.exports = {
18+
meta: {
19+
docs: {},
20+
schema: [schema],
21+
},
22+
23+
create: context => ({
24+
JSXOpeningElement: (node) => {
25+
const type = elementType(node);
26+
27+
if (type && type !== 'iframe') {
28+
return;
29+
}
30+
31+
const title = getPropValue(getProp(node.attributes, 'title'));
32+
33+
if (title && typeof title === 'string') {
34+
return;
35+
}
36+
37+
context.report({
38+
node,
39+
message: errorMessage,
40+
});
41+
},
42+
}),
43+
};

0 commit comments

Comments
 (0)