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' }],
+ },
+ ],
+});