Skip to content

Commit a55391a

Browse files
Add template-link-href-attributes rule with tests and docs
Co-authored-by: NullVoxPopuli <[email protected]>
1 parent f1d9ee3 commit a55391a

6 files changed

Lines changed: 144 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ npm-debug.log
1414

1515
# eslint-remote-tester
1616
eslint-remote-tester-results
17+
package-lock.json

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ rules in templates can be disabled with eslint directives with mustache or html
174174
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
175175
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
176176

177+
### Accessibility
178+
179+
| Name | Description | 💼 | 🔧 | 💡 |
180+
| :--------------------------------------------------------------------------- | :-------------------------------------- | :- | :- | :- |
181+
| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | | | |
182+
177183
### Best Practices
178184

179185
| Name | Description | 💼 | 🔧 | 💡 |
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# ember/template-link-href-attributes
2+
3+
<!-- end auto-generated rule header -->
4+
5+
Requires `href` attribute on `<a>` elements.
6+
7+
Anchor elements should have an `href` attribute to be properly recognized as links by browsers and assistive technologies. If an element is meant to be interactive but not navigate, use a `<button>` instead.
8+
9+
## Rule Details
10+
11+
This rule ensures that all `<a>` elements have an `href` attribute.
12+
13+
## Examples
14+
15+
Examples of **incorrect** code for this rule:
16+
17+
```gjs
18+
<template>
19+
<a>Link</a>
20+
</template>
21+
```
22+
23+
```gjs
24+
<template>
25+
<a onclick={{this.handleClick}}>Click me</a>
26+
</template>
27+
```
28+
29+
```gjs
30+
<template>
31+
<a role="button">Action</a>
32+
</template>
33+
```
34+
35+
Examples of **correct** code for this rule:
36+
37+
```gjs
38+
<template>
39+
<a href="/about">About Us</a>
40+
</template>
41+
```
42+
43+
```gjs
44+
<template>
45+
<a href="https://example.com">External Link</a>
46+
</template>
47+
```
48+
49+
```gjs
50+
<template>
51+
<button {{on "click" this.handleClick}}>Click me</button>
52+
</template>
53+
```
54+
55+
## References
56+
57+
- [MDN: The Anchor element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
58+
- [WebAIM: Links and Hypertext](https://webaim.org/techniques/hypertext/)
59+
- [ember-template-lint link-href-attributes](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/link-href-attributes.md)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'problem',
5+
docs: {
6+
description: 'require href attribute on link elements',
7+
category: 'Accessibility',
8+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-link-href-attributes.md',
9+
},
10+
fixable: null,
11+
schema: [],
12+
messages: {
13+
missingHref:
14+
'<a> elements must have an href attribute. Use <button> for clickable elements that are not links.',
15+
},
16+
},
17+
18+
create(context) {
19+
return {
20+
GlimmerElementNode(node) {
21+
if (node.tag !== 'a') {
22+
return;
23+
}
24+
25+
const hasHref = node.attributes?.some((attr) => attr.name === 'href');
26+
27+
if (!hasHref) {
28+
context.report({
29+
node,
30+
messageId: 'missingHref',
31+
});
32+
}
33+
},
34+
};
35+
},
36+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
},
6161
"dependencies": {
6262
"@ember-data/rfc395-data": "^0.0.4",
63+
"@glimmer/env": "^0.1.7",
6364
"css-tree": "^3.0.1",
6465
"ember-eslint-parser": "^0.5.9",
6566
"ember-rfc176-data": "^0.3.18",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//------------------------------------------------------------------------------
2+
// Requirements
3+
//------------------------------------------------------------------------------
4+
5+
const rule = require('../../../lib/rules/template-link-href-attributes');
6+
const RuleTester = require('eslint').RuleTester;
7+
8+
//------------------------------------------------------------------------------
9+
// Tests
10+
//------------------------------------------------------------------------------
11+
12+
const ruleTester = new RuleTester({
13+
parser: require.resolve('ember-eslint-parser'),
14+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
15+
});
16+
17+
ruleTester.run('template-link-href-attributes', rule, {
18+
valid: [
19+
'<template><a href="/about">About</a></template>',
20+
'<template><a href="https://example.com">External</a></template>',
21+
'<template><button>Click me</button></template>',
22+
],
23+
24+
invalid: [
25+
{
26+
code: '<template><a>Link</a></template>',
27+
output: null,
28+
errors: [{ messageId: 'missingHref' }],
29+
},
30+
{
31+
code: '<template><a onclick="doSomething()">Click</a></template>',
32+
output: null,
33+
errors: [{ messageId: 'missingHref' }],
34+
},
35+
{
36+
code: '<template><a role="button">Action</a></template>',
37+
output: null,
38+
errors: [{ messageId: 'missingHref' }],
39+
},
40+
],
41+
});

0 commit comments

Comments
 (0)