From 02c44c0ed18a52852a85a8831ef595f3aa05b44d Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 19 Feb 2026 16:30:24 -0500
Subject: [PATCH] Extract rule: template-no-action-modifiers
---
README.md | 1 +
docs/rules/template-no-action-modifiers.md | 64 +++++++++++++++++++
lib/rules/template-no-action-modifiers.js | 42 ++++++++++++
.../lib/rules/template-no-action-modifiers.js | 51 +++++++++++++++
4 files changed, 158 insertions(+)
create mode 100644 docs/rules/template-no-action-modifiers.md
create mode 100644 lib/rules/template-no-action-modifiers.js
create mode 100644 tests/lib/rules/template-no-action-modifiers.js
diff --git a/README.md b/README.md
index 384e45ca98..330bed0756 100644
--- a/README.md
+++ b/README.md
@@ -190,6 +190,7 @@ rules in templates can be disabled with eslint directives with mustache or html
| Name | Description | 💼 | 🔧 | 💡 |
| :----------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- |
| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
+| [template-no-action-modifiers](docs/rules/template-no-action-modifiers.md) | disallow usage of {{action}} modifiers | | | |
| [template-no-arguments-for-html-elements](docs/rules/template-no-arguments-for-html-elements.md) | disallow @arguments on HTML elements | | | |
| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | |
| [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | | | |
diff --git a/docs/rules/template-no-action-modifiers.md b/docs/rules/template-no-action-modifiers.md
new file mode 100644
index 0000000000..d62ca80549
--- /dev/null
+++ b/docs/rules/template-no-action-modifiers.md
@@ -0,0 +1,64 @@
+# ember/template-no-action-modifiers
+
+
+
+💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`.
+
+Disallow usage of `{{action}}` modifiers in templates.
+
+The `{{action}}` modifier has been deprecated in favor of the `{{on}}` modifier. The `{{on}}` modifier provides a more explicit and flexible way to handle events.
+
+## Rule Details
+
+This rule disallows using `{{action}}` as an element modifier.
+
+## Examples
+
+### Incorrect ❌
+
+```gjs
+
+
+
+```
+
+```gjs
+
+ Click me
+
+```
+
+```gjs
+
+
+
+```
+
+### Correct ✅
+
+```gjs
+
+
+
+```
+
+```gjs
+
+ Click me
+
+```
+
+```gjs
+
+
+
+```
+
+## Related Rules
+
+- [template-no-action](./template-no-action.md)
+
+## References
+
+- [Ember Octane Guide - Element Modifiers](https://guides.emberjs.com/release/components/template-lifecycle-dom-and-modifiers/)
+- [eslint-plugin-ember template-no-action](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-action.md)
diff --git a/lib/rules/template-no-action-modifiers.js b/lib/rules/template-no-action-modifiers.js
new file mode 100644
index 0000000000..5aa37f74be
--- /dev/null
+++ b/lib/rules/template-no-action-modifiers.js
@@ -0,0 +1,42 @@
+/** @type {import('eslint').Rule.RuleModule} */
+module.exports = {
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'disallow usage of {{action}} modifiers',
+ category: 'Best Practices',
+ strictGjs: true,
+ strictGts: true,
+ url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-action-modifiers.md',
+ },
+ fixable: null,
+ schema: [],
+ messages: {
+ noActionModifier: 'Do not use action modifiers. Use on modifier with a function instead.',
+ },
+ },
+
+ create(context) {
+ function checkForActionModifier(node) {
+ // Check if this is an action modifier (not action helper in mustache)
+ if (
+ node.path &&
+ node.path.type === 'GlimmerPathExpression' &&
+ node.path.original === 'action' &&
+ node.path.head?.type !== 'AtHead' &&
+ node.path.head?.type !== 'ThisHead'
+ ) {
+ context.report({
+ node,
+ messageId: 'noActionModifier',
+ });
+ }
+ }
+
+ return {
+ GlimmerElementModifierStatement(node) {
+ checkForActionModifier(node);
+ },
+ };
+ },
+};
diff --git a/tests/lib/rules/template-no-action-modifiers.js b/tests/lib/rules/template-no-action-modifiers.js
new file mode 100644
index 0000000000..ad9debaa67
--- /dev/null
+++ b/tests/lib/rules/template-no-action-modifiers.js
@@ -0,0 +1,51 @@
+const rule = require('../../../lib/rules/template-no-action-modifiers');
+const RuleTester = require('eslint').RuleTester;
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('ember-eslint-parser'),
+ parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
+});
+
+ruleTester.run('template-no-action-modifiers', rule, {
+ valid: [
+ '',
+ 'Hover
',
+ '',
+ '{{action "myAction"}}',
+ '{{this.action}}',
+ '{{@action}}',
+ ],
+
+ invalid: [
+ {
+ code: '',
+ output: null,
+ errors: [
+ {
+ message: 'Do not use action modifiers. Use on modifier with a function instead.',
+ type: 'GlimmerElementModifierStatement',
+ },
+ ],
+ },
+ {
+ code: 'Click me
',
+ output: null,
+ errors: [
+ {
+ message: 'Do not use action modifiers. Use on modifier with a function instead.',
+ type: 'GlimmerElementModifierStatement',
+ },
+ ],
+ },
+ {
+ code: '',
+ output: null,
+ errors: [
+ {
+ message: 'Do not use action modifiers. Use on modifier with a function instead.',
+ type: 'GlimmerElementModifierStatement',
+ },
+ ],
+ },
+ ],
+});