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
- 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? - Run axe DevTools — the
identical-links-same-purposerule flags duplicates with different destinations. - 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.
Related rules
- axe: link-name — empty or unlabelled links.
- axe: identical-links-same-purpose — duplicates pointing to different destinations.
- axe: link-in-text-block — link not distinguishable without colour.
- WCAG 2.4.9 Link Purpose (Link Only).