From 679e572f5e048237cbb6562de71e4f01945ce3bc Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:41:42 -0500 Subject: [PATCH] Extract rule: template-no-aria-unsupported-elements --- README.md | 11 ++-- .../template-no-aria-unsupported-elements.md | 61 +++++++++++++++++++ .../template-no-aria-unsupported-elements.js | 58 ++++++++++++++++++ .../template-no-aria-unsupported-elements.js | 33 ++++++++++ 4 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 docs/rules/template-no-aria-unsupported-elements.md create mode 100644 lib/rules/template-no-aria-unsupported-elements.js create mode 100644 tests/lib/rules/template-no-aria-unsupported-elements.js diff --git a/README.md b/README.md index 118014a552..8384aad365 100644 --- a/README.md +++ b/README.md @@ -178,11 +178,12 @@ rules in templates can be disabled with eslint directives with mustache or html ### Accessibility -| Name | Description | 💼 | 🔧 | 💡 | -| :------------------------------------------------------------------------------- | :-------------------------------------- | :- | :- | :- | -| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | | | | -| [template-no-abstract-roles](docs/rules/template-no-abstract-roles.md) | disallow abstract ARIA roles | | | | -| [template-no-accesskey-attribute](docs/rules/template-no-accesskey-attribute.md) | disallow accesskey attribute | | 🔧 | | +| Name                                  | Description | 💼 | 🔧 | 💡 | +| :------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- | :- | :- | :- | +| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | | | | +| [template-no-abstract-roles](docs/rules/template-no-abstract-roles.md) | disallow abstract ARIA roles | | | | +| [template-no-accesskey-attribute](docs/rules/template-no-accesskey-attribute.md) | disallow accesskey attribute | | 🔧 | | +| [template-no-aria-unsupported-elements](docs/rules/template-no-aria-unsupported-elements.md) | disallow ARIA roles, states, and properties on elements that do not support them | | | | ### Best Practices diff --git a/docs/rules/template-no-aria-unsupported-elements.md b/docs/rules/template-no-aria-unsupported-elements.md new file mode 100644 index 0000000000..20d50c826f --- /dev/null +++ b/docs/rules/template-no-aria-unsupported-elements.md @@ -0,0 +1,61 @@ +# ember/template-no-aria-unsupported-elements + + + +Disallows using ARIA roles, states, and properties on elements that do not support them. + +Certain HTML elements do not support ARIA roles, states, and properties. This rule helps ensure that ARIA attributes are only used on elements that support them, improving accessibility. + +## Rule Details + +This rule disallows ARIA attributes on elements that do not support them, including: + +- `meta` +- `html` +- `script` +- `style` +- `title` +- `base` +- `head` +- `link` + +## Examples + +Examples of **incorrect** code for this rule: + +```gjs + +``` + +```gjs + +``` + +```gjs + +``` + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## References + +- [WAI-ARIA in HTML](https://www.w3.org/TR/html-aria/) +- [ember-template-lint no-aria-unsupported-elements](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-aria-unsupported-elements.md) diff --git a/lib/rules/template-no-aria-unsupported-elements.js b/lib/rules/template-no-aria-unsupported-elements.js new file mode 100644 index 0000000000..079d13be28 --- /dev/null +++ b/lib/rules/template-no-aria-unsupported-elements.js @@ -0,0 +1,58 @@ +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: + 'disallow ARIA roles, states, and properties on elements that do not support them', + category: 'Accessibility', + strictGjs: true, + strictGts: true, + url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-aria-unsupported-elements.md', + }, + fixable: null, + schema: [], + messages: { + unsupported: + 'ARIA attribute "{{attribute}}" is not supported on <{{element}}> elements. Consider using a different element.', + }, + }, + + create(context) { + // Elements that don't support ARIA + const ELEMENTS_WITHOUT_ARIA_SUPPORT = new Set([ + 'meta', + 'html', + 'script', + 'style', + 'title', + 'base', + 'head', + 'link', + ]); + + return { + GlimmerElementNode(node) { + if (ELEMENTS_WITHOUT_ARIA_SUPPORT.has(node.tag)) { + const ariaAttributes = node.attributes?.filter( + (attr) => + attr.type === 'GlimmerAttrNode' && + attr.name && + (attr.name.startsWith('aria-') || attr.name === 'role') + ); + + for (const attr of ariaAttributes || []) { + context.report({ + node: attr, + messageId: 'unsupported', + data: { + attribute: attr.name, + element: node.tag, + }, + }); + } + } + }, + }; + }, +}; diff --git a/tests/lib/rules/template-no-aria-unsupported-elements.js b/tests/lib/rules/template-no-aria-unsupported-elements.js new file mode 100644 index 0000000000..c3fb87648e --- /dev/null +++ b/tests/lib/rules/template-no-aria-unsupported-elements.js @@ -0,0 +1,33 @@ +const rule = require('../../../lib/rules/template-no-aria-unsupported-elements'); +const RuleTester = require('eslint').RuleTester; + +const ruleTester = new RuleTester({ + parser: require.resolve('ember-eslint-parser'), + parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, +}); + +ruleTester.run('template-no-aria-unsupported-elements', rule, { + valid: [ + '', + '', + '', + ], + + invalid: [ + { + code: '', + output: null, + errors: [{ messageId: 'unsupported' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'unsupported' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'unsupported' }], + }, + ], +});