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 + +``` + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## 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: [ + ``, + ``, + ], + + 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: ``, + output: ``, + errors: [ + { + type: 'GlimmerAttrNode', + }, + ], + }, + ], +});