From fc1532a7786b632d98b443b4c176c28ceb79c388 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Tue, 17 Feb 2026 15:40:20 -0500
Subject: [PATCH] Extract rule: template-builtin-component-arguments
---
README.md | 9 ++-
.../template-builtin-component-arguments.md | 77 +++++++++++++++++++
.../template-builtin-component-arguments.js | 45 +++++++++++
.../template-builtin-component-arguments.js | 48 ++++++++++++
4 files changed, 175 insertions(+), 4 deletions(-)
create mode 100644 docs/rules/template-builtin-component-arguments.md
create mode 100644 lib/rules/template-builtin-component-arguments.js
create mode 100644 tests/lib/rules/template-builtin-component-arguments.js
diff --git a/README.md b/README.md
index 1997fcd7ea..9ce688b8a4 100644
--- a/README.md
+++ b/README.md
@@ -176,10 +176,11 @@ rules in templates can be disabled with eslint directives with mustache or html
### Best Practices
-| Name | Description | 💼 | 🔧 | 💡 |
-| :--------------------------------------------------------- | :--------------------------------- | :- | :- | :- |
-| [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 | | | |
+| Name | Description | 💼 | 🔧 | 💡 |
+| :----------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- |
+| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
+| [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 | | | |
### Components
diff --git a/docs/rules/template-builtin-component-arguments.md b/docs/rules/template-builtin-component-arguments.md
new file mode 100644
index 0000000000..72fba89b9e
--- /dev/null
+++ b/docs/rules/template-builtin-component-arguments.md
@@ -0,0 +1,77 @@
+# ember/template-builtin-component-arguments
+
+
+
+✅ The `extends: 'recommended'` property in a configuration file enables this rule.
+
+The builtin `Input` component has several arguments that match attributes
+of the lower-case `input` HTML element. These arguments should be set via e.g.
+`@type`, instead of `type`, but it is easy to forget and can cause subtle
+issues.
+
+This rule warns about `Input` component invocations that use the following attributes instead of arguments:
+
+- `checked`
+- `type`
+- `value`
+
+The builtin `Textarea` component has several arguments that match properties
+of the lower-case `textarea` HTML element. These arguments should be set via e.g.
+`@value`, instead of `value`, but it is easy to forget and can cause subtle
+issues.
+
+This rule warns about `Textarea` component invocations that use the following attributes instead of arguments:
+
+- `value`
+
+Please note that this rule currently only warns about these three attributes on
+the `Input`, and one property on the `Textarea` components, but might be extended in the future to also warn about
+other attributes or builtin components.
+
+## Examples
+
+This rule **forbids** the following:
+
+```hbs
+
+```
+
+```hbs
+
+```
+
+```hbs
+
+```
+
+This rule **allows** the following:
+
+```hbs
+
+```
+
+```hbs
+
+```
+
+```hbs
+
+```
+
+```hbs
+
+```
+
+## Migration
+
+- Add the `@` character in front of the relevant attributes to convert them
+ into component argument
+
+## Related Rules
+
+- [template-no-unknown-arguments-for-builtin-components](template-no-unknown-arguments-for-builtin-components.md)
+
+## References
+
+- [`Input` component API documentation](https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/Input?anchor=Input)
+- [`Textarea` component API documentation](https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/Textarea?anchor=Textarea)
diff --git a/lib/rules/template-builtin-component-arguments.js b/lib/rules/template-builtin-component-arguments.js
new file mode 100644
index 0000000000..8e91f5f24c
--- /dev/null
+++ b/lib/rules/template-builtin-component-arguments.js
@@ -0,0 +1,45 @@
+const FORBIDDEN_ATTRIBUTES = {
+ Input: new Set(['checked', 'type', 'value']),
+ Textarea: new Set(['value']),
+};
+
+function generateErrorMessage(component, attribute) {
+ return `Setting the \`${attribute}\` attribute on the builtin <${component}> component is not allowed. Did you mean \`@${attribute}\`?`;
+}
+
+/** @type {import('eslint').Rule.RuleModule} */
+module.exports = {
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'disallow setting certain attributes on builtin components',
+ category: 'Best Practices',
+ strictGjs: true,
+ strictGts: true,
+ url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-builtin-component-arguments.md',
+ },
+ fixable: null,
+ schema: [],
+ messages: {},
+ },
+
+ create(context) {
+ return {
+ GlimmerElementNode(node) {
+ const { tag, attributes } = node;
+ const forbiddenAttributes = FORBIDDEN_ATTRIBUTES[tag];
+
+ if (forbiddenAttributes && attributes) {
+ for (const attribute of attributes) {
+ if (attribute.name && forbiddenAttributes.has(attribute.name)) {
+ context.report({
+ node: attribute,
+ message: generateErrorMessage(tag, attribute.name),
+ });
+ }
+ }
+ }
+ },
+ };
+ },
+};
diff --git a/tests/lib/rules/template-builtin-component-arguments.js b/tests/lib/rules/template-builtin-component-arguments.js
new file mode 100644
index 0000000000..09cfb15cf1
--- /dev/null
+++ b/tests/lib/rules/template-builtin-component-arguments.js
@@ -0,0 +1,48 @@
+const rule = require('../../../lib/rules/template-builtin-component-arguments');
+const RuleTester = require('eslint').RuleTester;
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('ember-eslint-parser'),
+ parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
+});
+
+ruleTester.run('template-builtin-component-arguments', rule, {
+ valid: [
+ '',
+ '',
+ '',
+ '',
+ ],
+ invalid: [
+ {
+ code: '',
+ output: null,
+ errors: [
+ {
+ message:
+ 'Setting the `type` attribute on the builtin component is not allowed. Did you mean `@type`?',
+ },
+ ],
+ },
+ {
+ code: '',
+ output: null,
+ errors: [
+ {
+ message:
+ 'Setting the `checked` attribute on the builtin component is not allowed. Did you mean `@checked`?',
+ },
+ ],
+ },
+ {
+ code: '',
+ output: null,
+ errors: [
+ {
+ message:
+ 'Setting the `value` attribute on the builtin