From d2c4dad627768283014022a687257d8858b8f7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Mon, 27 Apr 2026 21:26:40 +0200 Subject: [PATCH 1/3] feat: add template-no-invalid-link-href --- README.md | 1 + docs/rules/template-no-invalid-link-href.md | 51 ++++++ lib/rules/template-no-invalid-link-href.js | Bin 0 -> 3628 bytes lib/utils/static-attr-value.js | 64 ++++++++ .../rules/template-no-invalid-link-href.js | 154 ++++++++++++++++++ tests/lib/utils/static-attr-value-test.js | 129 +++++++++++++++ 6 files changed, 399 insertions(+) create mode 100644 docs/rules/template-no-invalid-link-href.md create mode 100644 lib/rules/template-no-invalid-link-href.js create mode 100644 lib/utils/static-attr-value.js create mode 100644 tests/lib/rules/template-no-invalid-link-href.js create mode 100644 tests/lib/utils/static-attr-value-test.js diff --git a/README.md b/README.md index dafcfd0640..ea7516a68b 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ To disable a rule for an entire `.gjs`/`.gts` file, use a regular ESLint file-le | [template-no-heading-inside-button](docs/rules/template-no-heading-inside-button.md) | disallow heading elements inside button elements | ๐Ÿ“‹ | | | | [template-no-invalid-aria-attributes](docs/rules/template-no-invalid-aria-attributes.md) | disallow invalid aria-* attributes | ๐Ÿ“‹ | | | | [template-no-invalid-interactive](docs/rules/template-no-invalid-interactive.md) | disallow non-interactive elements with interactive handlers | ๐Ÿ“‹ | | | +| [template-no-invalid-link-href](docs/rules/template-no-invalid-link-href.md) | disallow invalid href values on anchor elements | | | | | [template-no-invalid-link-text](docs/rules/template-no-invalid-link-text.md) | disallow invalid or uninformative link text content | ๐Ÿ“‹ | | | | [template-no-invalid-link-title](docs/rules/template-no-invalid-link-title.md) | disallow invalid title attributes on link elements | ๐Ÿ“‹ | | | | [template-no-invalid-role](docs/rules/template-no-invalid-role.md) | disallow invalid ARIA roles | ๐Ÿ“‹ | | | diff --git a/docs/rules/template-no-invalid-link-href.md b/docs/rules/template-no-invalid-link-href.md new file mode 100644 index 0000000000..42e9ba5948 --- /dev/null +++ b/docs/rules/template-no-invalid-link-href.md @@ -0,0 +1,51 @@ +# ember/template-no-invalid-link-href + + + +Disallow link elements โ€” `` and `` โ€” whose `href` value is a commonly-misused placeholder (e.g. `href="#"`, `href=""`, `href="javascript:..."`). Both carry URL semantics per HTML ยง4.5.1 / ยง4.8.14, so the same validity rules apply on each. + +This rule is **pragmatic accessibility/UX guidance, not spec enforcement.** Values like `href="#"` and `href="javascript:void(0)"` are technically valid URLs per the [HTML spec](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element); the rule flags them because they are widely-recognized anti-patterns for faking a clickable anchor: + +- Breaks expected keyboard behavior (anchors should navigate; buttons should act) +- The `javascript:` pseudo-protocol is [called out as an anti-pattern by MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#javascript_pseudo-protocol) +- Leaves assistive tech announcing a link that doesn't navigate + +If a click handler is what you want, use a `