Skip to content

Links with the same name need the same purpose

  • Rule: axe/identical-links-same-purpose
  • Checks: Links with the same name must have a similar purpose
  • WCAG: 2.4.9
  • Fix class: content: A fix needs authored text.
  • People who use a screen reader or a braille display, most of them blind.
  • People with cognitive, learning or attention disabilities.
Section titled “Repeated links such as “Read more” go to different pages”

Make each name say where its link goes, using the title of the item it opens. Link that title itself, or keep the short visible words and add the title after them as visually hidden text inside the link.

<a href="/guides/spring-planting">Read more<span class="visually-hidden"> about spring planting</span></a>
Section titled “Each row of a list or table repeats an action link such as “Edit””

Add the row’s item to each name. Give the link and the text that names the item an id each, and point the link’s aria-labelledby at both, the link first.

<ul>
<li><span id="order-1042">Order 1042</span> <a href="/orders/1042/edit" id="edit-1042" aria-labelledby="edit-1042 order-1042">Edit</a></li>
<li><span id="order-1043">Order 1043</span> <a href="/orders/1043/edit" id="edit-1043" aria-labelledby="edit-1043 order-1043">Edit</a></li>
</ul>
Section titled “The links reach the same content by different URLs”

Links that lead to the same content share a purpose, so nothing needs to change: confirm it and record the review. Pointing them all at one canonical URL also stops axe asking.

Section titled “Numbering the links, such as “Read more 1” and “Read more 2””

The names differ, so axe stops asking, but they still do not say where each link goes.

Section titled “Writing an aria-label that drops the visible words, such as aria-label="Spring planting" on a “Read more” link”

Voice control users who say “Read more” can no longer reach the link, and axe reports it under label-content-name-mismatch. Keep the visible words at the start of the name.

Section titled “Telling the links apart with title attributes”

A link with text takes its name from that text, so the names stay identical. The title becomes only a description, and it shows only on mouse hover.

The part of the fix that differs in React, in its syntax. The rest of the guidance holds.

Section titled “A row component repeats an action link such as “Edit” for each item”

Call useId in the row component and build both IDs from it, so each row’s aria-labelledby points at that row’s own text. Take the item’s words from its props.

function OrderRow({ order }) {
const id = useId();
return (
<li>
<span id={`${id}-name`}>Order {order.number}</span>{' '}
<a href={`/orders/${order.number}/edit`} id={`${id}-edit`} aria-labelledby={`${id}-edit ${id}-name`}>
Edit
</a>
</li>
);
}

Building the IDs from the array index or Math.random()

Section titled “Building the IDs from the array index or Math.random()”

Index IDs repeat when the list renders twice on a page, and random IDs differ between the server and the client render, so hydration reports a mismatch. useId is unique and stable.

axe-core’s documentation of the rule

CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.