Skip to content

Commit 91c766e

Browse files
committed
PR Review
1 parent 544b9f3 commit 91c766e

3 files changed

Lines changed: 45 additions & 75 deletions

File tree

docs/rules/template-no-duplicate-landmark-elements.md

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,68 @@
22

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

5-
Disallows duplicate landmark elements without unique labels.
6-
7-
HTML5 landmark elements (like `<nav>`, `<header>`, `<footer>`, etc.) help screen reader users navigate a page. When multiple landmarks of the same type exist, each must have a unique label to distinguish them.
5+
If multiple landmark elements of the same type are found on a page, they must each have a unique label (provided by `aria-label` or `aria-labelledby`).
86

97
## Rule Details
108

11-
This rule ensures that when multiple landmark elements of the same type appear in a template, each has a unique `aria-label` or `aria-labelledby` attribute.
12-
13-
Landmark elements checked:
9+
List of elements & their corresponding roles:
1410

1511
- `header` (banner)
16-
- `footer` (contentinfo)
1712
- `main` (main)
18-
- `nav` (navigation)
1913
- `aside` (complementary)
20-
- `section` (region)
2114
- `form` (form, search)
15+
- `nav` (navigation)
16+
- `footer` (contentinfo)
2217

2318
## Examples
2419

25-
Examples of **incorrect** code for this rule:
20+
This rule **forbids** the following:
2621

27-
```gjs
28-
<template>
29-
<nav>Primary Navigation</nav>
30-
<nav>Secondary Navigation</nav>
31-
</template>
22+
```hbs
23+
<nav></nav>
24+
<nav></nav>
3225
```
3326

34-
```gjs
35-
<template>
36-
<header>Site Header</header>
37-
<header>Article Header</header>
38-
</template>
27+
```hbs
28+
<nav></nav>
29+
<div role='navigation'></div>
3930
```
4031

41-
Examples of **correct** code for this rule:
32+
```hbs
33+
<nav aria-label='site navigation'></nav>
34+
<nav aria-label='site navigation'></nav>
35+
```
36+
37+
```hbs
38+
<form aria-label='search-form'></form>
39+
<form aria-label='search-form'></form>
40+
```
41+
42+
This rule **allows** the following:
43+
44+
```hbs
45+
<nav aria-label='primary site navigation'></nav>
46+
<nav aria-label='secondary site navigation within home page'></nav>
47+
```
4248

43-
```gjs
44-
<template>
45-
<nav aria-label="Primary Navigation">Links</nav>
46-
<nav aria-label="Secondary Navigation">More Links</nav>
47-
</template>
49+
```hbs
50+
<nav aria-label='primary site navigation'></nav>
51+
<div role='navigation' aria-label='secondary site navigation within home page'></div>
4852
```
4953

50-
```gjs
51-
<template>
52-
<header aria-label="Site Header">Site Logo</header>
53-
<header aria-label="Article Header">Article Title</header>
54-
</template>
54+
```hbs
55+
<form aria-label='shipping address'></form>
56+
<form aria-label='billing address'></form>
5557
```
5658

57-
```gjs
58-
<template>
59-
<nav aria-labelledby="nav-1">
60-
<h2 id="nav-1">Main Menu</h2>
61-
</nav>
62-
<nav aria-labelledby="nav-2">
63-
<h2 id="nav-2">Side Menu</h2>
64-
</nav>
65-
</template>
59+
```hbs
60+
<form role='search' aria-label='search'></form>
61+
<form aria-labelledby='form-title'><div id='form-title'>Meaningful Form Title</div></form>
6662
```
6763

6864
## References
6965

70-
- [ARIA Landmarks](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/)
71-
- [eslint-plugin-ember template-no-duplicate-landmark-elements](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-duplicate-landmark-elements.md)
66+
- [WAI-ARIA specification: Landmark Roles](https://www.w3.org/WAI/PF/aria/roles#landmark_roles)
67+
- [Understanding Success Criterion 1.3.1: Info and Relationships](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)
68+
- [Using aria-labelledby to name regions and landmarks](https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA13.html)
69+
- [Using aria-label to provide labels for objects](https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA6)

lib/rules/template-no-duplicate-landmark-elements.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
schema: [],
1313
messages: {
1414
duplicate:
15-
'Duplicate <{{element}}> landmark element found. Each landmark must have a unique label.',
15+
'If multiple landmark elements (or elements with an equivalent role) of the same type are found on a page, they must each have a unique label.',
1616
},
1717
originallyFrom: {
1818
name: 'ember-template-lint',
@@ -30,7 +30,6 @@ module.exports = {
3030
main: 'main',
3131
nav: 'navigation',
3232
aside: 'complementary',
33-
section: 'region',
3433
form: 'form',
3534
};
3635

@@ -97,7 +96,6 @@ module.exports = {
9796
context.report({
9897
node: unlabeled[i].node,
9998
messageId: 'duplicate',
100-
data: { element: unlabeled[i].tag },
10199
});
102100
}
103101
} else {
@@ -106,7 +104,6 @@ module.exports = {
106104
context.report({
107105
node: entry.node,
108106
messageId: 'duplicate',
109-
data: { element: entry.tag },
110107
});
111108
}
112109
}
@@ -126,7 +123,6 @@ module.exports = {
126123
context.report({
127124
node: groupEntries[i].node,
128125
messageId: 'duplicate',
129-
data: { element: groupEntries[i].tag },
130126
});
131127
}
132128
}

tests/lib/rules/template-no-duplicate-landmark-elements.js

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,19 @@ const ruleTester = new RuleTester({
88

99
ruleTester.run('template-no-duplicate-landmark-elements', rule, {
1010
valid: [
11-
'<template><header aria-label="Main">Header</header></template>',
12-
'<template><nav aria-label="Primary">Nav 1</nav><nav aria-label="Secondary">Nav 2</nav></template>',
13-
'<template><main>Content</main></template>',
14-
15-
// Nav + div with role="navigation" (different unique labels)
11+
'<template><nav aria-label="primary site navigation"></nav><nav aria-label="secondary site navigation within home page"></nav></template>',
1612
'<template><nav aria-label="primary site navigation"></nav><div role="navigation" aria-label="secondary site navigation within home page"></div></template>',
17-
18-
// Form with aria-labelledby + another form with aria-label (unique labels)
1913
'<template><form aria-labelledby="form-title"><div id="form-title">Shipping Address</div></form><form aria-label="meaningful title of second form"></form></template>',
20-
21-
// Standard page layout (unique landmarks by type)
14+
'<template><form role="search"></form><form></form></template>',
2215
'<template><header></header><main></main><footer></footer></template>',
23-
24-
// role="none" — not a landmark, should be ignored
2516
'<template><img role="none"><img role="none"></template>',
26-
2717
// Conditional branches: elements in if/else are mutually exclusive
2818
'<template>{{#if this.isCreateProjectFromSavedSearchEnabled}}<form></form>{{else}}<form></form>{{/if}}</template>',
19+
// header inside sectioning element loses landmark role
20+
"<template><main><header><h1>Main Page Header</h1></header></main><dialog id='my-dialog'><header><h1>Dialog Header</h1></header></dialog></template>",
2921
],
3022

3123
invalid: [
32-
{
33-
code: '<template><nav>Nav 1</nav><nav>Nav 2</nav></template>',
34-
output: null,
35-
errors: [{ messageId: 'duplicate' }],
36-
},
37-
{
38-
code: '<template><header>Header 1</header><header>Header 2</header></template>',
39-
output: null,
40-
errors: [{ messageId: 'duplicate' }],
41-
},
42-
{
43-
code: '<template><aside>Side 1</aside><aside>Side 2</aside></template>',
44-
output: null,
45-
errors: [{ messageId: 'duplicate' }],
46-
},
47-
4824
{
4925
code: '<template><nav></nav><nav></nav></template>',
5026
output: null,

0 commit comments

Comments
 (0)