From 562a732e1af7b0a679bb3654dc2cfab3a537478f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:54:17 -0500 Subject: [PATCH] Extract rule: template-no-input-placeholder --- README.md | 1 + docs/rules/template-no-input-placeholder.md | 47 ++++++++++++ lib/rules/template-no-input-placeholder.js | 36 +++++++++ .../rules/template-no-input-placeholder.js | 74 +++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 docs/rules/template-no-input-placeholder.md create mode 100644 lib/rules/template-no-input-placeholder.js create mode 100644 tests/lib/rules/template-no-input-placeholder.js diff --git a/README.md b/README.md index 26fd0ffeea..f87c310bb8 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ rules in templates can be disabled with eslint directives with mustache or html | [template-no-chained-this](docs/rules/template-no-chained-this.md) | disallow redundant `this.this` in templates | | 🔧 | | | [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | | | [template-no-element-event-actions](docs/rules/template-no-element-event-actions.md) | disallow element event actions (use {{on}} modifier instead) | | | | +| [template-no-input-placeholder](docs/rules/template-no-input-placeholder.md) | disallow placeholder attribute on input elements | | | | | [template-no-input-tagname](docs/rules/template-no-input-tagname.md) | disallow tagName attribute on {{input}} helper | | | | | [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | | | | diff --git a/docs/rules/template-no-input-placeholder.md b/docs/rules/template-no-input-placeholder.md new file mode 100644 index 0000000000..638b52af25 --- /dev/null +++ b/docs/rules/template-no-input-placeholder.md @@ -0,0 +1,47 @@ +# ember/template-no-input-placeholder + + + +Disallows `placeholder` attribute on input elements. + +## Rule Details + +The `placeholder` attribute should not be used as it has accessibility issues. Use proper labels instead. + +## Examples + +Examples of **incorrect** code for this rule: + +```gjs + +``` + +```gjs + +``` + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## References + +- [eslint-plugin-ember template-no-input-placeholder](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-input-placeholder.md) +- [Placeholders in Form Fields Are Harmful](https://www.nngroup.com/articles/form-design-placeholders/) diff --git a/lib/rules/template-no-input-placeholder.js b/lib/rules/template-no-input-placeholder.js new file mode 100644 index 0000000000..553b9caf3a --- /dev/null +++ b/lib/rules/template-no-input-placeholder.js @@ -0,0 +1,36 @@ +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'disallow placeholder attribute on input elements', + category: 'Best Practices', + strictGjs: true, + strictGts: true, + url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-input-placeholder.md', + }, + fixable: null, + schema: [], + messages: { + noPlaceholder: + 'Do not use placeholder attribute. Use a label instead for better accessibility.', + }, + }, + + create(context) { + return { + GlimmerElementNode(node) { + if (node.tag === 'input' && node.attributes) { + for (const attr of node.attributes) { + if (attr.type === 'GlimmerAttrNode' && attr.name === 'placeholder') { + context.report({ + node: attr, + messageId: 'noPlaceholder', + }); + } + } + } + }, + }; + }, +}; diff --git a/tests/lib/rules/template-no-input-placeholder.js b/tests/lib/rules/template-no-input-placeholder.js new file mode 100644 index 0000000000..1d9168f362 --- /dev/null +++ b/tests/lib/rules/template-no-input-placeholder.js @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/template-no-input-placeholder'); +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-input-placeholder', rule, { + valid: [ + ``, + ``, + ``, + ], + + invalid: [ + { + code: ``, + output: null, + errors: [ + { + message: + 'Do not use placeholder attribute. Use a label instead for better accessibility.', + type: 'GlimmerAttrNode', + }, + ], + }, + { + code: ``, + output: null, + errors: [ + { + message: + 'Do not use placeholder attribute. Use a label instead for better accessibility.', + type: 'GlimmerAttrNode', + }, + ], + }, + { + code: ``, + output: null, + errors: [ + { + message: + 'Do not use placeholder attribute. Use a label instead for better accessibility.', + type: 'GlimmerAttrNode', + }, + ], + }, + ], +});