From 6cb63ef172bb538d27e7f82040e9e618e7ee29c0 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Tue, 17 Feb 2026 19:03:50 -0500
Subject: [PATCH] Extract rule: template-no-accesskey-attribute
---
README.md | 7 ++-
docs/rules/template-no-accesskey-attribute.md | 44 ++++++++++++++
lib/rules/template-no-accesskey-attribute.js | 48 ++++++++++++++++
.../rules/template-no-accesskey-attribute.js | 57 +++++++++++++++++++
4 files changed, 153 insertions(+), 3 deletions(-)
create mode 100644 docs/rules/template-no-accesskey-attribute.md
create mode 100644 lib/rules/template-no-accesskey-attribute.js
create mode 100644 tests/lib/rules/template-no-accesskey-attribute.js
diff --git a/README.md b/README.md
index 97b3525387..349ee6e3f4 100644
--- a/README.md
+++ b/README.md
@@ -176,9 +176,10 @@ 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 | | | |
+| Name | Description | 💼 | 🔧 | 💡 |
+| :------------------------------------------------------------------------------- | :-------------------------------------- | :- | :- | :- |
+| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | | | |
+| [template-no-accesskey-attribute](docs/rules/template-no-accesskey-attribute.md) | disallow accesskey attribute | | 🔧 | |
### Best Practices
diff --git a/docs/rules/template-no-accesskey-attribute.md b/docs/rules/template-no-accesskey-attribute.md
new file mode 100644
index 0000000000..79ec754f3d
--- /dev/null
+++ b/docs/rules/template-no-accesskey-attribute.md
@@ -0,0 +1,44 @@
+# ember/template-no-accesskey-attribute
+
+🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
+
+
+
+Disallows the use of `accesskey` attribute on elements.
+
+The `accesskey` attribute creates inconsistencies between keyboard shortcuts and keyboard commands used by screen readers and keyboard-only users, causing accessibility issues.
+
+## Examples
+
+Examples of **incorrect** code for this rule:
+
+```gjs
+
+
+
+```
+
+```gjs
+
+ Home
+
+```
+
+Examples of **correct** code for this rule:
+
+```gjs
+
+
+
+```
+
+```gjs
+
+ Home
+
+```
+
+## References
+
+- [eslint-plugin-ember no-accesskey-attribute](https://github.com/eslint-plugin-ember/eslint-plugin-ember/blob/master/docs/rule/no-accesskey-attribute.md)
+- [WebAIM: Keyboard Accessibility - Accesskey](https://webaim.org/techniques/keyboard/accesskey)
diff --git a/lib/rules/template-no-accesskey-attribute.js b/lib/rules/template-no-accesskey-attribute.js
new file mode 100644
index 0000000000..9ebd7ec6ee
--- /dev/null
+++ b/lib/rules/template-no-accesskey-attribute.js
@@ -0,0 +1,48 @@
+/** @type {import('eslint').Rule.RuleModule} */
+module.exports = {
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'disallow accesskey attribute',
+ category: 'Accessibility',
+ strictGjs: true,
+ strictGts: true,
+ url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-accesskey-attribute.md',
+ },
+ fixable: 'code',
+ schema: [],
+ messages: {
+ noAccesskey:
+ 'No access key attribute allowed. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreader and keyboard only users create accessibility complications.',
+ },
+ },
+
+ create(context) {
+ return {
+ GlimmerElementNode(node) {
+ const accesskeyAttr = node.attributes?.find((attr) => attr.name === 'accesskey');
+
+ if (accesskeyAttr) {
+ context.report({
+ node: accesskeyAttr,
+ messageId: 'noAccesskey',
+ fix(fixer) {
+ // Remove the attribute including preceding whitespace
+ const sourceCode = context.sourceCode;
+ const text = sourceCode.getText();
+ const attrStart = accesskeyAttr.range[0];
+ const attrEnd = accesskeyAttr.range[1];
+
+ let removeStart = attrStart;
+ while (removeStart > 0 && /\s/.test(text[removeStart - 1])) {
+ removeStart--;
+ }
+
+ return fixer.removeRange([removeStart, attrEnd]);
+ },
+ });
+ }
+ },
+ };
+ },
+};
diff --git a/tests/lib/rules/template-no-accesskey-attribute.js b/tests/lib/rules/template-no-accesskey-attribute.js
new file mode 100644
index 0000000000..a5a915b3f3
--- /dev/null
+++ b/tests/lib/rules/template-no-accesskey-attribute.js
@@ -0,0 +1,57 @@
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require('../../../lib/rules/template-no-accesskey-attribute');
+const RuleTester = require('eslint').RuleTester;
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('ember-eslint-parser'),
+ parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
+});
+
+ruleTester.run('template-no-accesskey-attribute', rule, {
+ valid: [
+ `
+
+ `,
+ `
+ Content
+ `,
+ ],
+
+ invalid: [
+ {
+ code: `
+
+ `,
+ output: `
+
+ `,
+ errors: [
+ {
+ message:
+ 'No access key attribute allowed. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreader and keyboard only users create accessibility complications.',
+ type: 'GlimmerAttrNode',
+ },
+ ],
+ },
+ {
+ code: `
+ Home
+ `,
+ output: `
+ Home
+ `,
+ errors: [
+ {
+ type: 'GlimmerAttrNode',
+ },
+ ],
+ },
+ ],
+});