Accessibility pattern · Navigation

Links that say where they go

A link's words should say where it goes, even read on their own in a screen reader's list of links: a file says its type and size, and a new tab says so before it opens. Links in text are underlined, so they never depend on color, and anything that acts on the page rather than going somewhere is a button.

WCAG criteria
7
Keyboard rules
3
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

Keyboard

Keys it answers to

Every action works without a pointer.

KeyWhat it does
Tab or ShiftTabMoves through the links and buttons in reading order, each with a visible focus ring.
EnterFollows the focused link. The external one opens in a new tab; the demo's own pages do not exist here, so a note says what would happen.
Enter or SpaceOn a button, does its job on this page: copies the link, or shows the list of link names.

Screen readers

What it announces

Written from the roles, names and states in the markup.

WhenExpected announcement
Tab reaches the first linkhow we chose the villages, link
Tab reaches the external linkrainfall data from IMD Pune (opens in a new tab), link
Tab reaches the downloadAnnual report 2025–26, PDF, 2.4 MB, link
Tab reaches a Read more linkRead more about the water committees in Khatav, link
Copy link to this update is pressedLink copied

These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

Code

Copy the code

The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

The markup

<div class="ap-links" data-ap-links>
  <article class="ap-links__card">
    <p class="ap-links__kicker">Annual update</p>
    <h3 class="ap-links__name">A year of village ponds</h3>
    <p class="ap-links__text">This year our volunteers cleared silt from 42 ponds across Satara and Sangli, and the monsoon filled every one. Read <a href="/ponds/how-we-chose/">how we chose the villages</a>, or see this year's <a href="https://www.imdpune.gov.in/" target="_blank" rel="noopener">rainfall data from IMD Pune<svg class="ap-links__ext" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg><span class="ap-links__vh"> (opens in a new tab)</span></a>.</p>

    <a class="ap-links__file" href="/reports/annual-report-2025-26.pdf" download>
      <span class="ap-links__badge" aria-hidden="true" translate="no">PDF</span>
      <span class="ap-links__file-text">
        <span class="ap-links__file-name">Annual report 2025–26<span class="ap-links__vh">,</span></span>
        <span class="ap-links__file-meta">PDF, 2.4 MB</span>
      </span>
      <svg class="ap-links__dl" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4v11M7 10l5 5 5-5M5 20h14"/></svg>
    </a>

    <h4 class="ap-links__sub">More from the field</h4>
    <ul class="ap-links__stories">
      <li class="ap-links__story">
        <p class="ap-links__story-name">Water committees run by women</p>
        <p class="ap-links__story-text">Nine villages in Khatav now look after their own ponds.</p>
        <a class="ap-links__more" href="/stories/water-committees/">Read more<span class="ap-links__vh"> about the water committees in Khatav</span><svg class="ap-links__arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
      </li>
      <li class="ap-links__story">
        <p class="ap-links__story-name">Birds are back at the ponds</p>
        <p class="ap-links__story-text">Volunteers counted 61 species in one January weekend.</p>
        <a class="ap-links__more" href="/stories/bird-count/">Read more<span class="ap-links__vh"> about the bird count</span><svg class="ap-links__arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
      </li>
    </ul>

    <h4 class="ap-links__sub">Link or button?</h4>
    <div class="ap-links__versus">
      <div class="ap-links__case">
        <p class="ap-links__case-k">Goes to another page: a link</p>
        <a class="ap-links__more" href="/projects/">View all projects<svg class="ap-links__arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
      </div>
      <div class="ap-links__case">
        <p class="ap-links__case-k">Does something here: a button</p>
        <button type="button" class="ap-btn ap-links__copy"><svg class="ap-btn__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>Copy link to this update</button>
      </div>
    </div>
    <p class="ap-links__status" role="status"></p>
  </article>

  <div class="ap-links__names">
    <button type="button" class="ap-links__reveal" aria-expanded="false" aria-controls="links-list">
      <span>Show these links as a screen reader lists them</span>
      <svg class="ap-links__chevron" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6"/></svg>
    </button>
    <div class="ap-links__panel" id="links-list" hidden>
      <p class="ap-links__panel-k">Each link's name, out of context:</p>
      <ol></ol>
    </div>
  </div>
</div>

WCAG 2.2

What it meets

The success criteria this pattern takes care of, and how.

  • 1.4.1 Use of Color Level A

    Links in text are underlined, so they stand out from the words around them without relying on color.

  • 2.4.4 Link Purpose (In Context) Level A

    Each link's text, with the sentence around it, says where it goes; visually hidden words fill in the rest.

  • 2.4.9 Link Purpose (Link Only) Level AAA

    Even read alone, as in a links list, every name is specific: no two links share the name Read more.

  • 2.4.7 Focus Visible Level AA

    Every link and button shows a two-pixel focus ring, and the underline stays while it is focused.

  • 2.5.3 Label in Name Level A

    Hidden words are added after the visible ones, so the name starts with what is on screen and voice commands match it.

  • 3.2.5 Change on Request Level AAA

    The link that opens a new tab says so in its name and with an icon, before it is followed.

  • 4.1.2 Name, Role, Value Level A

    Going somewhere is a link and doing something here is a button, so each is announced with the role people expect.

Usage

When to use it

Use it

  • Any text with links: articles, cards, help pages, emails.
  • Lists of teasers where every item ends in Read more.

Use something else

  • Actions on the page, like copying, opening a panel or submitting: use a button.
  • Opening a new tab for every external link: do it only when leaving the page would lose work.

Common failures

How it usually goes wrong

  • Click here and Read more

    In a list of links, ten "Read more" links are ten identical choices. Visually hidden words make each one say what it is about.

  • Links shown only by color

    Blue text in grey text is hard to spot for many people, and impossible for some. An underline marks a link in any color.

  • A new tab without warning

    The back button stops working and screen reader users may not notice the new tab. The link says it opens one, in words and with an icon.

  • Downloads that surprise

    A link that starts a large download, or opens a PDF on a phone, costs time and data. Saying the type and size lets people choose.

  • A link that acts like a button

    A link with href="#" that copies or opens something is announced as a link, so people expect to go somewhere. Use a button.

  • aria-label that replaces the visible words

    aria-label="Water committees" on a link that shows Read more breaks voice control. Add hidden words after the visible ones instead.

Notes

Building it

  • Visually hidden text keeps the design short while giving screen reader users the full name; put it after the visible words so the name still starts with what people see.
  • Browsers let :visited change only colors, for privacy, so the underline does the work of marking a link and the visited color is an extra.
  • The download attribute asks the browser to save the file rather than open it; the type and size in the link let people decide before they tap.
  • The list above is built from each link's text, skipping parts marked aria-hidden, which is roughly what a screen reader's links list shows.

Sources: Understanding WCAG 2.2: Link purpose (in context) · WCAG technique G201: Warning before a new window opens

Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction