Skip to content

Latest commit

 

History

History
51 lines (37 loc) · 2.91 KB

File metadata and controls

51 lines (37 loc) · 2.91 KB

ember/template-no-invalid-link-href

Disallow link elements — <a> and <area> — whose href value is a commonly-misused placeholder (e.g. href="#", href="", href="javascript:..."). Both carry URL semantics per the HTML spec (the <a> element, the <area> element), 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; 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
  • Leaves assistive tech announcing a link that doesn't navigate

If a click handler is what you want, use a <button>. If you want a genuine fragment link, use href="#section-id".

Complements template-link-href-attributes, which handles the missing href case. This rule validates the href value.

Examples

This rule forbids the following:

<template>
  <a href="#">Click</a>
  <a href="#!">Click</a>
  <a href="">Click</a>
  <a href>Click</a>
  <a href="javascript:void(0)">Click</a>
  <a href="JavaScript:alert(1)">Execute</a>
</template>

This rule allows the following:

<template>
  <a href="/x">Link</a>
  <a href="https://example.com">Link</a>
  <a href="#section">Fragment link</a>
  <a href="mailto:[email protected]">Email</a>
  <a href={{this.url}}>Dynamic</a>
</template>

Mustache hrefs whose value is a static literal (string, number, or boolean) are validated — the rule unwraps them to their static value via getStaticAttrValue. Only truly dynamic mustaches (PathExpressions, helpers with arguments, or concat statements that include a dynamic part) are skipped, because we can't statically determine what they will resolve to at runtime.

References