( Operable / WCAG 2.4.9 )

Links with the same accessible name go to different places

MinorLevel AAAWCAG 2.4.9 — Link Purpose (Link Only)

What is this issue?

Two or more <a> elements on the same page resolve to the exact same accessible name (via visible text, aria-label, or aria-labelledby), but their href attributes point at different destinations. The links work correctly; the problem is that nothing in their announced name distinguishes one from the other.

This is a cross-link comparison, not a property of any single link in isolation. A single “Read more” link is a separate, related problem (see Link text is generic and gives no context); this rule specifically fires when the same name appears on multiple links that don’t lead to the same place.

Why does this matter?

Most screen readers offer a dedicated links list (NVDA and JAWS with Insert+F7, VoiceOver through the Rotor) that pulls every link on the page into a flat menu with no surrounding paragraph text. That list is exactly where this rule’s failure becomes visible: ten links that all read “Read more” appear as ten identical entries, with nothing in the list itself to say which one leads to which article.

A sighted user scanning the same page has visual position and surrounding headings to disambiguate the links instantly. A screen reader user working from the links list has none of that context available: the whole value of a links list is that it lets them skip the surrounding text, which is precisely the information they’d need to tell these links apart.

Who is affected?

  • Screen reader users: pull up a links list expecting each entry to be distinguishable, and instead find several entries that read identically with no way to tell which leads where without leaving the list to re-read surrounding content.
  • Voice control users: issue a command like “click Read more” expecting one match; with several identically-named links on the page, voice software either guesses or prompts the user to choose from a numbered list, adding a step that wouldn’t exist with distinct names.
  • Cognitive disabilities: users who rely on link text as a memory aid while navigating lose that anchor point when several links share one name, making it harder to keep track of which link they’ve already visited or intend to use next.

What users experience

Priya uses JAWS on her Windows laptop to compare three vendor case studies linked from a partner’s resources page. She presses Insert+F7 to open the links list, expecting three distinguishable entries. Instead she hears “Read the case study, link” three times in a row, with no way to know which entry covers the healthcare client versus the retail client versus the logistics client. She closes the list and has to read through the full page instead, abandoning the exact shortcut the links list exists to provide.

How do I fix it?

Make each link’s accessible name specific to its own destination, so that reading any one entry from a links list tells the user exactly where it goes. This works because it fixes the accessible name at its source: the same fix that helps a screen reader user in a links list also helps a voice control user issuing a unique command and a sighted user scanning quickly.

When editing the visible text isn’t an option (a card-based design where every link must read “Read more” for visual consistency), add a distinct aria-label to each link instead. This keeps the visible design unchanged while giving assistive technology a name specific enough to tell the links apart, since aria-label overrides the announced name without touching what’s rendered on screen.

Code Examples

Before
<h3>Accessible forms</h3>
<a href="/blog/forms">Read more</a>

<h3>Color contrast basics</h3>
<a href="/blog/contrast">Read more</a>
After
<!-- Method 1: rewrite the visible text (preferred) -->
<h3>Accessible forms</h3>
<a href="/blog/forms">Read more: Accessible forms</a>

<h3>Color contrast basics</h3>
<a href="/blog/contrast">Read more: Color contrast basics</a>

<!-- Method 2: aria-label when the visible text must stay identical -->
<h3>Accessible forms</h3>
<a href="/blog/forms" aria-label="Read more: Accessible forms">Read more</a>

<h3>Color contrast basics</h3>
<a href="/blog/contrast" aria-label="Read more: Color contrast basics">Read more</a>

Both fixed versions give each link an accessible name unique to its own destination (“Accessible forms” versus “Color contrast basics”) instead of the identical generic phrase both links shared before. Method 1 changes what every user sees and reads; Method 2 keeps the visible “Read more” text a card design might require, while giving assistive technology the distinguishing detail through aria-label.

Framework Examples

This failure is almost always produced by a single reusable component rendering a static string across a loop of items: fixing one rendered instance by hand doesn’t fix the underlying template, since the next item the CMS returns reproduces the same identical name.

function ArticleCard({ article }) {
  return (
    <article>
      <h3>{article.title}</h3>
      <a href={article.url} aria-label={`Read more: ${article.title}`}>
        Read more
      </a>
    </article>
  );
}

Interpolating the article’s own title into aria-label at the component level guarantees every rendered card gets a distinct accessible name automatically, no matter how many articles the list ends up containing; the fix scales with the data instead of needing to be reapplied by hand each time content changes.

Common Mistakes

Mistake: “The links are visually far apart on the page, so users can tell them apart.” Visual distance means nothing once a link is pulled into a links list or read by voice control software; both strip away surrounding position entirely and present the accessible name on its own. A fix that relies on visual layout doesn’t reach the users this rule protects.

Mistake: “Adding title attributes with different text fixes this.” The title attribute has inconsistent screen reader support for being read as part of an element’s announced name, and it’s never available at all to touch or keyboard-only users. Use aria-label or edit the visible text instead, since both are reliably exposed as the accessible name.

Mistake: “This is the same issue as generic link text, so fixing one fixes both.” They’re related but distinct checks. A page can have a single “Read more” link with no duplicate anywhere else; that fails the generic-link-text rule but not this one. A page can also have two links that both say “View pricing details,” which is specific enough to pass a generic-text check but still fails this rule if the two links lead to different pricing pages.

How RedFlag Detects This

Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s identical-links-same-purpose rule as part of every scan. This rule is one of six explicitly force-enabled beyond its default tag membership, so it runs even though 2.4.9 is a Level AAA criterion outside the WCAG A/AA tag set RedFlag otherwise restricts scans to. The check compares every link’s accessible name against every other link’s accessible name and flags pairs that match exactly while their href values differ.

False negative: the comparison is exact-match on the accessible name: two links reading “Read more” and “Read More” (different capitalization visible to a user, if the underlying comparison isn’t case-normalized) or two links that are near-duplicates but not byte-identical can evade the check depending on axe-core’s own normalization rules. False positive: two links that intentionally share a name because they lead to the same destination via different paths (a logo link and a “Home” text link both pointing at /) do not trigger this rule, since matching destinations are excluded; a genuine false positive here is uncommon. Manual step: open the page’s links list with a screen reader and manually confirm every identically-named entry that does slip past the exact-match check is still genuinely distinguishable in practice.

Manual Testing

  1. Open the page in Chrome or Firefox with NVDA or VoiceOver running.
  2. Pull up the links list (NVDA/JAWS: Insert+F7, then filter to Links; VoiceOver: open the Rotor and select Links).
  3. Scan for any repeated entries with identical text.
  4. For each repeated entry, activate both links in turn (in separate tabs, or by noting the destination) and confirm whether they lead to the same place.
  5. If two identically-named links lead to different destinations, the check fails: rewrite the text or add distinguishing aria-label values.

2.4.9 Link Purpose (Link Only): A link’s purpose must be determinable from its accessible name alone, without needing any surrounding context. This is a Level AAA criterion, stricter than the more commonly required Level A criterion 2.4.4 Link Purpose (In Context), which allows context from the enclosing sentence or paragraph to help clarify a link’s purpose. This rule enforces the AAA bar specifically for the case of duplicate names pointing at different places.

Link text is generic and gives no context is the more common, Level A version of a related problem: a link whose own text gives no clue to its destination, whether or not it’s duplicated elsewhere on the page.

Button or link has no accessible name is the more severe failure mode in the same family: a link with no name at all, rather than one sharing a name with another link.

Button or link has no accessible name covers the equivalent naming requirement for buttons, worth checking on any page where this rule’s duplicate-link pattern also shows up in a set of action buttons.

Page has no skip navigation link commonly co-occurs with this rule, since large repeated navigation menus are a frequent source of both a missing-bypass failure and duplicate-name link pairs.

Link is not distinguishable from surrounding text without color is a different link-purpose failure in the same neighborhood: links that are hard to identify visually rather than by name.

References

Frequently asked questions

Is this rule the same as flagging generic link text like "click here"?

No, though the two often overlap. Generic link text is a problem even when there is only one such link on a page, because it fails to describe any destination. This rule is specifically about two or more links sharing one identical name while pointing somewhere different, which is a comparison across links, not a judgment about any single link in isolation.

Is WCAG 2.4.9 a requirement I need to meet for AA conformance?

No. 2.4.9 Link Purpose (Link Only) is a Level AAA success criterion, the highest and most demanding conformance level, which most legal and organizational standards do not require. Treat this rule as gold-standard guidance worth applying where practical, not a blocker for a standard AA compliance target.

Does adding a different aria-label to each link fix this without changing the visible text?

Yes. Since the accessible name is what matters here, giving each link a distinct aria-label (for example aria-label="Read more about accessible forms" versus aria-label="Read more about color contrast") resolves the failure even if both links keep displaying identical visible text like "Read more."

Do two links that are both "empty" in some way, like two icon-only close buttons, trigger this rule?

Only if they share an identical accessible name and lead to different destinations. Two close buttons that both do the same thing (closing their own dialog) are not a violation even with the same name, since their function, not their destination, is identical. This rule is about link purpose, which centers on where a link leads.

Why is this rule only minor impact if it can genuinely confuse users?

The impact rating reflects that a workaround usually exists: a user can still read the surrounding sentence or heading to disambiguate two identically named links, even though that undermines the specific convenience a links list is meant to provide. It is real friction, but rarely a complete blocker to completing a task, which is why it is rated less severe than issues with no workaround at all.