Skip to main content
WCAG Patterns

WCAG 2.4.4 · Level A · WCAG 2.0

Link Purpose (In Context)

The purpose of each link can be determined from the link text alone, or from the link text together with its programmatically determined context.

Principle
Operable
Guideline
Navigable
Level
A
Added in
WCAG 2.0

What it really means

A user must be able to tell what a link does from its text alone, or from its text together with its programmatically determined context. Screen readers let users list every link on a page in isolation ("link list" mode). If your page has fifteen "Read more" links, that's fifteen identical entries in the list.

Who it helps

  • Screen-reader users navigating by link list.
  • Voice-control users ("click Read more" becomes ambiguous).
  • Search engines, which weigh link text as an anchor signal.
  • Everyone skimming — descriptive links communicate faster than surrounding prose.

How to test

  1. In your screen reader, open the links list (VoiceOver: ⌃⌥⌘U → Links; NVDA: Insert+F7). Can you tell where each link goes from the text alone or the text + immediate context?
  2. Run axe DevTools — the identical-links-same-purpose rule flags duplicates with different destinations.
  3. Read the page with CSS disabled. Links should still make sense.

A failing pattern

<article>
  <h3>The accessibility tax no one budgets for</h3>
  <p>We looked at 120 projects across five years…</p>
  <a href="/posts/accessibility-tax">Read more</a>
</article>
 
<article>
  <h3>Why your focus outline keeps disappearing</h3>
  <p>Reset stylesheets, design-system resets, hover states…</p>
  <a href="/posts/focus-outline">Read more</a>
</article>

Two links, same text, different destinations. Accessible link-list view: a sea of "Read more".

A passing pattern

Option A — rewrite the link to carry its purpose:

<article>
  <h3>The accessibility tax no one budgets for</h3>
  <p>We looked at 120 projects across five years…</p>
  <a href="/posts/accessibility-tax">
    Read the full report on the accessibility tax
  </a>
</article>

Option B — use programmatically determined context (heading):

<article aria-labelledby="post-1-title">
  <h3 id="post-1-title">The accessibility tax no one budgets for</h3>
  <p>We looked at 120 projects across five years…</p>
  <a
    href="/posts/accessibility-tax"
    aria-describedby="post-1-title"
  >
    Read more
  </a>
</article>

WCAG accepts the enclosing list item, paragraph, cell, or heading as "programmatically determined context". Modern screen readers announce aria-describedby after the link text in link-list mode. The fallback if you can't rewrite the link.

Option C — hide extra label text visually:

<a href="/posts/accessibility-tax">
  Read more
  <span className="sr-only"> about the accessibility tax</span>
</a>

The sr-only utility (visible to AT, hidden from sighted users) is in Tailwind and most design systems.

Notes and edge cases

  • Icon-only links (X/Twitter icon linking to your profile) need an accessible name — aria-label="Eric Nygren on X/Twitter" or visually hidden text.
  • Phone and email links<a href="tel:+46…">+46 70 123 4567</a> — fine. The visible number is the purpose.
  • AAA — WCAG 2.4.9 Link Purpose (Link Only) — raises the bar: the link text alone must be enough. No context fallback.