#accessibility.chat
Accessibility news, research, and Luke compliance assistant

Identical Link Text, Different Targets: A WCAG 2.4.4 Audit

MarcusSeattle area
digitalwcagscreen readersariaautomated testing

Marcus · AI Research Engine

Analytical lens: Operational Capacity

Digital accessibility, WCAG, web development

AI-assisted · Source-linked · Editorially reviewed · Methodology

Trust note

This article was drafted with AI assistance, reviewed against accessibility.chat editorial standards, and should be treated as research and education rather than legal advice. We prioritize primary sources and correct material errors.

Top view of crop anonymous female diabetic measuring blood sugar with glucometer over scattered lancets
Photo by Klaus Nielsen on Pexels

Automated accessibility audits catch fewer than 40% of real barriers. Research on testing methodology makes that ceiling painfully clear. So when automated analysis surfaces six distinct violations on a single test page, that's worth examining carefully — not because the number is shocking, but because the patterns it reveals repeat across production sites every day.

The test page at wcagrepo.netlify.app (opens in new window) was built to demonstrate a specific WCAG failure: identical link text pointing to different destinations. The automated scan found that problem, plus five more. Here's the full accounting.

The Primary Finding: WCAG 2.4.4 Link Purpose

The page's headline violation is WCAG 2.4.4 Link Purpose (In Context) (opens in new window). Three separate patterns demonstrate it:

Pattern 1 — Repeated "Details" links:

<!-- Bug: All three links read as "Details" with no distinguishing context -->
<p>Product A: $99 - <a href="/product-a">Details</a></p>
<p>Product B: $149 - <a href="/product-b">Details</a></p>
<p>Product C: $199 - <a href="/product-c">Details</a></p>

Pattern 2 — Repeated "View" links in a data table:

<!-- Bug: Identical "View" text, different order targets -->
<tr><td>#12345</td><td>2026-02-20</td><td><a href="/order/12345">View</a></td></tr>
<tr><td>#12346</td><td>2026-02-19</td><td><a href="/order/12346">View</a></td></tr>

Pattern 3 — Ambiguous "Edit" and "Delete" links:

<!-- Bug: Which item? The link text doesn't say -->
<td><a href="/edit/1">Edit</a> | <a href="/delete/1">Edit</a></td>

When a screen reader user pulls up the links list — a standard navigation technique in JAWS, NVDA, and VoiceOver — they hear "Details, Details, Details" with no way to distinguish which product each link targets. For keyboard-only users navigating linearly, the surrounding context may help, but for switch users or anyone using a links dialog, it's a dead end.

The fix is straightforward. Either use visually hidden text or aria-label to disambiguate:

<!-- Fix Option 1: visually hidden span -->
<a href="/product-a">Details <span class="visually-hidden">for Product A</span></a>

<!-- Fix Option 2: aria-label (overrides visible text entirely) -->
<a href="/product-a" aria-label="Details for Product A">Details</a>

<!-- Fix Option 3: aria-labelledby referencing adjacent content -->
<p id="product-a-name">Product A</p>
<a href="/product-a" aria-labelledby="product-a-name details-text">
  <span id="details-text">Details</span>
</a>

The page's own documentation notes that HAL (its automated remediation layer) resolves this by injecting aria-label values derived from nearby context — "Details for Product A", "View order #12345". That's a reasonable automated patch, but it's a remediation, not a fix. The underlying HTML should be authored correctly from the start.

Secondary Findings: Four More Violations

The automated analysis identified four additional issues beyond the headline WCAG 2.4.4 failure.

Missing Landmark Regions

The page lacks both a <nav> landmark and a <header>/banner landmark. This violates WCAG 1.3.6 Identify Purpose (opens in new window) and the broader landmark structure requirements under WCAG 1.3.1 Info and Relationships (opens in new window). Screen reader users rely on landmarks to jump between page regions without reading every element. A page with only a <main> landmark — which this page does have, and gets credit for — still leaves users without the navigational scaffolding they need.

<!-- Missing: wrap navigation in <nav> -->
<nav aria-label="Primary navigation">
  <ul><!-- nav items --></ul>
</nav>

<!-- Missing: wrap page header in <header> -->
<header>
  <a href="/">Site name</a>
  <!-- site-wide header content -->
</header>

Table Without Caption

The data table is missing a <caption> element. Under WCAG 1.3.1 Info and Relationships (opens in new window), the relationship between a table and its purpose must be programmatically determinable. Without a caption, a screen reader user landing on the table hears column headers with no framing — they don't know if they're looking at orders, products, or something else entirely.

<!-- Fix: add <caption> as first child of <table> -->
<table>
  <caption>Recent Orders</caption>
  <thead>...</thead>
  <tbody>...</tbody>
</table>

Table Headers Missing Scope

The <th> elements lack scope attributes. This compounds the caption problem. Without scope="col" or scope="row", screen readers cannot reliably associate header cells with their data cells, particularly in complex tables. WCAG 1.3.1 (opens in new window) requires that information conveyed through structure be available programmatically.

<!-- Fix: add scope to every <th> -->
<thead>
  <tr>
    <th scope="col">Order</th>
    <th scope="col">Date</th>
    <th scope="col">Action</th>
  </tr>
</thead>

What Passes — And Why It Matters

The page has a valid H1 and a <main> landmark. Both pass. That's not nothing — heading structure is one of the most commonly broken patterns on the web, and the presence of <main> shows at least some semantic awareness in the page's construction. It's a foundation to build from.

Applying This to Real Development

Identical link text is one of the patterns that automated testing tools miss most frequently when the surrounding DOM context makes the link technically distinguishable. The violations here are caught because the test page is constructed to surface them cleanly. In production, a linter or axe-core scan might pass these links if the tool evaluates programmatic context differently.

Three practical steps for development teams:

  1. Add a links-list audit to your QA checklist. Open NVDA or JAWS, pull up the links dialog (Insert+F7 in JAWS), and read through every link out of context. If any two links say the same thing but go different places, that's a violation.

  2. Enforce aria-label or visually-hidden text in your component library. If your design system has a "Details" button component, build the disambiguation in at the component level — not as a retrofit on every implementation.

  3. Require <caption> and scope in table code reviews. These are mechanical checks. A linting rule or PR template note catches them before they ship.

It's 2026, and "Details, Details, Details" is still one of the most common screen reader experiences on e-commerce sites. The fix is four words of HTML.

Language Access: The Layer Audits Ignore

None of the issues above are language-specific — but they become compounding barriers for multilingual users who rely on assistive technology. An aria-label of "Details for Product A" is only useful if that label is translated. Most accessibility audits stop at English. Most translation pipelines stop at visible text.

This is where idioma.chat (opens in new window) addresses a gap the broader tooling ecosystem hasn't solved: it translates not just the visible content but the full accessibility layer — aria-label values, alt text, form validation messages, modal content, and dynamically loaded strings. For the 25+ million people in the U.S. with limited English proficiency who also use assistive technology, an accessible English page that's inaccessible in Spanish isn't actually accessible. Title VI of the Civil Rights Act and Executive Order 13166 (opens in new window) require meaningful language access for federally funded programs — and that obligation extends to the programmatic accessibility layer, not just visible text.

CORS Perspective

Through the CORS framework's Operational lens, these six violations cluster into two categories: mechanical fixes (caption, scope, landmarks) that any developer can implement in under an hour, and architectural fixes (link disambiguation) that require a design system decision. The Community dimension is direct — screen reader users navigating product listings or order histories are blocked from basic task completion. The Risk dimension is real but secondary: WCAG 2.4.4 Link Purpose is a Level A criterion (opens in new window), meaning it's among the baseline requirements courts and the DOJ treat as non-negotiable. Strategically, the path forward is component-level enforcement — build the fix into the design system once, and it propagates everywhere. That's the 80/20 answer: one aria-label convention in your button component eliminates this class of violation across every page that uses it.

About the Marcus lens

Seattle-area accessibility consultant specializing in digital accessibility and web development. Former software engineer turned advocate for inclusive tech.

Marcus is an AI analyst lens, not a human staff member. It helps frame this article through a consistent accessibility perspective.

Specialization: Digital accessibility, WCAG, web development

View all articles using this lens →

Transparency Disclosure

This article was drafted with AI assistance and reviewed against our editorial methodology. We disclose that process so readers can judge the work clearly.