diff --git a/packages/eslint-plugin-template/docs/rules/accessibility-elements-content.md b/packages/eslint-plugin-template/docs/rules/accessibility-elements-content.md
index d1c596acb..c8b40585a 100644
--- a/packages/eslint-plugin-template/docs/rules/accessibility-elements-content.md
+++ b/packages/eslint-plugin-template/docs/rules/accessibility-elements-content.md
@@ -23,7 +23,17 @@ Ensures that the heading, anchor and button elements have content in it
## Rule Options
-The rule does not have any configuration options.
+The rule accepts an options object with the following properties:
+
+```ts
+interface Options {
+ /**
+ * Default: `["aria-label","innerHtml","innerHTML","innerText","outerHTML","title"]`
+ */
+ allowList?: string[];
+}
+
+```
@@ -113,26 +123,24 @@ The rule does not have any configuration options.
~~~~~~~~~~~~~~~~~
```
-
-
---
-
-✅ - Toggle examples of correct code for this rule
-
-
-
-#### Default Config
+#### Custom Config
```json
{
"rules": {
"@angular-eslint/template/accessibility-elements-content": [
- "error"
+ "error",
+ {
+ "allowList": [
+ "aria-labelledby"
+ ]
+ }
]
}
}
@@ -140,37 +148,14 @@ The rule does not have any configuration options.
-#### ✅ Valid Code
+#### ❌ Invalid Code
```html
-Heading Content!
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
-
-
-#### ✅ Valid Code
-
-```html
-
-```
+
@@ -178,29 +163,8 @@ The rule does not have any configuration options.
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-
-```
-
-
-
----
+
+✅ - Toggle examples of correct code for this rule
@@ -221,215 +185,19 @@ The rule does not have any configuration options.
#### ✅ Valid Code
```html
+Heading Content!
+
+
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
Anchor Content!
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
-```
-
-
-
----
-
-
-
-#### Default Config
-
-```json
-{
- "rules": {
- "@angular-eslint/template/accessibility-elements-content": [
- "error"
- ]
- }
-}
-```
-
-
-
-#### ✅ Valid Code
-
-```html
+
```
@@ -438,13 +206,19 @@ The rule does not have any configuration options.
-#### Default Config
+#### Custom Config
```json
{
"rules": {
"@angular-eslint/template/accessibility-elements-content": [
- "error"
+ "error",
+ {
+ "allowList": [
+ "appTooltipLabel",
+ "ariaLabel"
+ ]
+ }
]
}
}
@@ -455,7 +229,10 @@ The rule does not have any configuration options.
#### ✅ Valid Code
```html
-
+
+
+
+
```
diff --git a/packages/eslint-plugin-template/src/rules/accessibility-elements-content.ts b/packages/eslint-plugin-template/src/rules/accessibility-elements-content.ts
index 6c7985ab5..7812ffd99 100644
--- a/packages/eslint-plugin-template/src/rules/accessibility-elements-content.ts
+++ b/packages/eslint-plugin-template/src/rules/accessibility-elements-content.ts
@@ -5,17 +5,24 @@ import {
} from '../utils/create-eslint-rule';
import { isHiddenFromScreenReader } from '../utils/is-hidden-from-screen-reader';
-type Options = [];
+type Options = [
+ {
+ readonly allowList?: readonly string[];
+ },
+];
export type MessageIds = 'accessibilityElementsContent';
export const RULE_NAME = 'accessibility-elements-content';
-const safelistAttributes: ReadonlySet = new Set([
+const DEFAULT_SAFELIST_ATTRIBUTES: readonly string[] = [
'aria-label',
'innerHtml',
'innerHTML',
'innerText',
'outerHTML',
'title',
-]);
+];
+const DEFAULT_OPTIONS: Options[0] = {
+ allowList: DEFAULT_SAFELIST_ATTRIBUTES,
+};
export default createESLintRule({
name: RULE_NAME,
@@ -26,13 +33,25 @@ export default createESLintRule({
'Ensures that the heading, anchor and button elements have content in it',
recommended: false,
},
- schema: [],
+ schema: [
+ {
+ additionalProperties: false,
+ properties: {
+ allowList: {
+ items: { type: 'string' },
+ type: 'array',
+ uniqueItems: true,
+ },
+ },
+ type: 'object',
+ },
+ ],
messages: {
accessibilityElementsContent: '<{{element}}> should have content',
},
},
- defaultOptions: [],
- create(context) {
+ defaultOptions: [DEFAULT_OPTIONS],
+ create(context, [{ allowList }]) {
const parserServices = getTemplateParserServices(context);
return {
@@ -42,6 +61,10 @@ export default createESLintRule({
if (isHiddenFromScreenReader(node)) return;
const { attributes, inputs, name: element, sourceSpan } = node;
+ const safelistAttributes: ReadonlySet = new Set([
+ ...DEFAULT_SAFELIST_ATTRIBUTES,
+ ...(allowList ?? []),
+ ]);
const hasAttributeSafelisted = [...attributes, ...inputs]
.map(({ name }) => name)
.some((inputName) => safelistAttributes.has(inputName));
diff --git a/packages/eslint-plugin-template/tests/rules/accessibility-elements-content/cases.ts b/packages/eslint-plugin-template/tests/rules/accessibility-elements-content/cases.ts
index c4336e630..6c9fd49a8 100644
--- a/packages/eslint-plugin-template/tests/rules/accessibility-elements-content/cases.ts
+++ b/packages/eslint-plugin-template/tests/rules/accessibility-elements-content/cases.ts
@@ -4,19 +4,34 @@ import type { MessageIds } from '../../../src/rules/accessibility-elements-conte
const messageId: MessageIds = 'accessibilityElementsContent';
export const valid = [
- 'Heading Content! ',
- ' ',
- ' ',
- ' ',
- 'Anchor Content! ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
+ `
+ Heading Content!
+
+
+
+ Anchor Content!
+
+
+
+
+
+
+
+
+ `,
+ {
+ code: `
+
+
+
+
+ `,
+ options: [
+ {
+ allowList: ['appTooltipLabel', 'ariaLabel'],
+ },
+ ],
+ },
];
export const invalid = [
@@ -47,4 +62,15 @@ export const invalid = [
messageId,
data: { element: 'button' },
}),
+ convertAnnotatedSourceToFailureCase({
+ messageId,
+ description:
+ 'should fail if attribute/input/directive is not configured in allowList',
+ annotatedSource: `
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ `,
+ options: [{ allowList: ['aria-labelledby'] }],
+ data: { element: 'button' },
+ }),
];