Link Purpose (Link Only)
A mechanism is available to identify the purpose of each link from the link text alone, except where the purpose is ambiguous to all users.
Who this affects
Screen reader users navigating by link list, without needing to inspect surrounding context to work out where each link goes.
The failure and the fix
Each example below is a self-contained page, loaded in a frame so its markup cannot affect this page. Open either one on its own to test it with a keyboard or screen reader.
Fails 2.4.9
Open the failing example in a new tab
fail.html — the problem
<h1>Support</h1>
<!-- This page PASSES 2.4.4 Link Purpose (In Context) at Level A: each "Read
more" sits inside its own list item with a heading, so its purpose can be
worked out from the programmatically determined context.
It FAILS 2.4.9 at AAA, which drops the "in context" allowance. The link
text ALONE must identify the purpose - because that is how a screen reader
user navigating by link list actually encounters it: stripped of all
surrounding content. -->
<ul>
<li>
<h2>Delivery and collection</h2>
<p>How long orders take and where to collect them.</p>
<a href="#a">Read more</a>
</li>
<li>
<h2>Returns</h2>
<p>Our 30-day returns policy.</p>
<a href="#b">Read more</a>
</li>
<li>
<h2>Accessibility</h2>
<p>Step-free access and hearing loops at our shops.</p>
<a href="#c">Read more</a>
</li>
</ul>
<p id="a">Delivery.</p><p id="b">Returns.</p><p id="c">Accessibility.</p>
Meets 2.4.9
Open the passing example in a new tab
pass.html — the fix
<h1>Support</h1>
<!-- FIX 1: the heading is the link. The link text alone says where it goes,
and the target is larger for everyone (2.5.8). -->
<ul>
<li>
<h2><a href="#a">Delivery and collection</a></h2>
<p>How long orders take and where to collect them.</p>
</li>
<li>
<h2><a href="#b">Returns policy</a></h2>
<p>Our 30-day returns policy.</p>
</li>
<li>
<h2><a href="#c">Accessibility at our shops</a></h2>
<p>Step-free access and hearing loops.</p>
</li>
</ul>
<!-- FIX 2: where a design insists on a repeated call to action, extend the
accessible name with visually hidden text. The visible words must remain
inside the name so speech-input users can still say them (2.5.3). -->
<p><a href="#a">Read more<span class="visually-hidden"> about delivery and collection</span></a></p>
<!-- Test it the way a screen reader user experiences it: open the rotor or
press Insert+F7 in NVDA to list every link on the page, and read the list
with the page hidden. Every entry should make sense on its own.
The exception: links whose purpose is ambiguous TO ALL USERS are allowed -
a "random article" link is genuinely unpredictable for everyone, so it
does not fail. -->
<p id="a">Delivery.</p><p id="b">Returns.</p><p id="c">Accessibility.</p>
How to test it
Read every link's accessible name in isolation. Each must be self-explanatory. "Read more about our refund policy" passes where "Read more" fails.
-
Automated
Generic link text can be pattern-matched, but the judgement of self-sufficiency is human.
This demo's failure is not machine-detectable. Every link on the failing page has text, so axe's link-name rule is satisfied. Deciding that "Read more" fails to identify its destination requires reading the page and understanding what each link points at - which is judgement, not pattern matching.
Relevant axe rules:
link-name
-
Keyboard
Unplug the mouse. Move through the page with Tab, Shift+Tab, Enter, Space and the arrow keys. See the keyboard testing script.
-
Screen reader
Listen to both examples with NVDA, JAWS, VoiceOver or TalkBack and compare what is announced. See the screen reader cheat sheets.
-
Visual
Zoom to 200% and 400%, narrow the viewport to 320 px, and apply the text-spacing overrides. See the visual testing procedures.
Related criteria
In the specification
- Understanding 2.4.9 Link Purpose (Link Only) — the W3C explanation, intent and exceptions
- 2.4.9 in the WCAG 2.2 Recommendation — the normative wording
WCAG 2.2 Demo Suite