Deep dive: crafting accessible links
Posted:
The humble link. A small but mighty, fundamental piece of HTML that's arguably the backbone of the entire web. Links are everywhere, and we use them thousands of times a day, but what goes into making a link truly accessible? In this post, I'm going to deep drive into link accessibility, covering the basics, things to avoid, and some common problematic patterns.
So grab a drink, some snacks, and strap in.
Foundations
Accessible names and roles
You’ll see the terms "accessible role" and "accessible name" used throughout this post. They describe what assistive technology, such as screen readers, exposes to users.
- The role tells assistive tech what something is and how it behaves. Native HTML elements come with built-in roles. For example, an
<a>with ahrefhas the role of “link”. Generic container elements like<div>and<span>carry no semantic meaning. - Roles can be explicitly set with the
roleattribute. This is generally only necessary when not using native HTML or in rare cases where the default needs to be changed. - The accessible name is the label announced alongside the role. For links, this is usually the text inside the
<a></a>tags.
If you want to dig deeper, see the MDN pages on WAI-ARIA roles and accessible names.
Use semantic markup
Let's start with the basics: when is a link actually a link?
If an anchor tag <a> has a href, it's a hyperlink:
<a href="https://www.jamesjacobs.me">James Jacobs</a>
Native elements have semantic meaning and behaviour built in. Taking the example above:
- It's keyboard accessible. You can Tab to it and activate with Enter.
- It looks like a link (blue with an underline) in all common browsers.
- It's announced as a link by screen readers.
- It navigates somewhere when activated.
A link is not just something that looks clickable. It’s a specific element with built-in meaning and behaviour. However, not all links are created (or coded) equally...
If you are involved with accessibility testing, you’ve probably seen something like this:
<a id="some-id-for-js">Link text</a>
Can you spot the difference? There's no href.
Sometimes, developers omit the href attribute and use JavaScript to handle navigation. The problem is that, according to the HTML living standard, an <a> element without an href is just a placeholder for where a link might have been placed.
If the a element has no href attribute, then the element represents a placeholder for where a link might otherwise have been placed, if it had been relevant, consisting of just the element's contents.
Without a href, an <a> element does not have the role "link". It falls back to role "generic". It won’t be announced as a link by screen readers and won’t appear in lists of links. Semantically, it’s not much different from a <span>.
Another common inaccessible pattern is along the lines of:
<div tabindex="0">Link text</div>
In both cases, the developer has to recreate the behaviour and semantics that a native link would have provided, by adding:
- JavaScript to handle navigation and activation.
tabindex="0"to make it keyboard focusable, as a<div>, or a<a>without ahref, can't be tabbed to via the keyboard.role="link"so assistive technology recognises it as a link.- Custom styling to make it look like a link.
There are other shortcomings, too. For example, the CSS :link pseudo-class won't apply styles to <a> tags without a href.
Semantic HTML provides a lot of out of the box functionaility, so use it wherever possible.
Links vs buttons
All too often, links and buttons are used interchangeably. This creates a number of issues. Simply put: links go places and buttons do things.
- If it navigates somewhere, on the page or to a different page, use a
<a>with the relevanthref. - If it triggers an action, such as opening a menu, revealing content, submitting a form, or opening a modal, use a
<button>.
Why is this important? Native HTML elements have semantic meaning and set expectations on how they will behave when encountered and interacted with. When someone activates a link, they expect navigation. When they activate a button, they expect an action.
- Screen reader users hearing a link announced will expect to go somewhere if they activate it.
- Screen readers can list elements of a certain type on the page, including links - so users expect things that behave like a link to be listed there.
- Keyboard users expect to be able to tab to interactive elements, like links and buttons, and activate a link with Enter and a button with Space or Enter.
When the wrong element is used, those expectations may not be met. For example, when developers do things like:
<a href="#" role="button" id="id-for-javascript">View Details</a>
That element is programmatically presented as a button (imagine it's visually presented as one too). A screen reader will announce it as a button, due to the role. A user might reasonably press Space to activate it. But unless additional JavaScript has been added to handle the Space key, nothing happens. The element looks like a button, sounds like a button, but does not behave like one - that's confusing.
Use the right element for the job. Native elements already include the correct semantics, keyboard behaviour, and assistive technology support.
Writing accessible link text
Make the destination clear
Link text should make it clear where the link leads.
Links are not always read in context. Screen reader users can pull up a list of links on a page and move through them one by one. Being presented with a list of "click here" or "read more" provides no useful information to go on.
When reviewing or writing links, try reading them on their own. If the surrounding paragraph disappeared, would the destination still be obvious?
Don't: use ambiguous link text
Click here to learn how to test with screen readers.
Do: make it clear where the link leads
Learn more about how to test with screen readers.
A recommended approach is to use the target page's <title> text as the link text, assuming the title is descriptive. In the example above, the target page has a page <title> that starts with "How to test with a screen reader", therefore, the same is used for the link text.
While WCAG 2.4.4 Link Purpose (In Context) (Level A) allows for link context to be provided by text in the same paragraph, list item, table cell or header, this doesn't help screen reader users navigating from link to link or when reviewing a list of links out of context.
Keep link text concise
Avoid linking whole sentences or large blocks of text. Long links can be difficult and time-consuming to listen to in a screen reader and potentially awkward to activate with speech recognition software.
Instead, link just enough words to make the destination clear.
Don't: link unnecessary words
<p>
<a href="/training-videos">
You can find out more about accessibility
by watching our free accessibility training videos
</a>
</p>Do: link enough to preserve meaning
<p>
You can find out more about accessibility
by watching our
<a href="/training-videos">
free accessibility training videos
</a>
</p>Use consistent wording
If multiple links point to the same page, use the same link text.
WCAG 3.2.4 Consistent Identification (Level AA), requires components that have the same function, within a set of pages, to be identified consistently. It's a good idea to use the same link text for the same destination, even on links in a single page.
Consistency reduces cognitive load. It helps people build a mental model of your interface and move through it with confidence.
Don't: use different link text for the same destination
<!-- Page 1 -->
<a href="/contact">Contact us</a>
<!-- Page 2 -->
<a href="/contact">Get in touch</a>Do: be consistent with link text
<!-- Page 1 -->
<a href="/contact">Contact us</a>
<!-- Page 2 -->
<a href="/contact">Contact us</a>Include the file type and size in the link text
When linking to non-HTML documents, let the user know the type and the size of file they are opening.
Do: inform the user of the file type and size
<a href="sales-figures-jan-2026.pdf">
Sales figures Jan 2026 (PDF, 2MB)
</a>Avoid using raw URLs as link text
Linked URLs are:
- Hard to read at a glance: long strings of slashes, numbers, and tracking parameters are difficult to read, scan and understand
- Unclear and sometimes suspicious: A shortened link gives no indication of where it leads. For example, where does https://tinyurl.com/yetpupyz actually go?
- Difficult to follow with screen readers: which read them character by character, e.g., "H T T P S colon slash slash W W W dot james jacobs dot me slash guides slash how dash to dash test dash with dash a dash screen dash reader"
Don't: link RAW URLs
<a href="https://tinyurl.com/yetpupyz">
https://tinyurl.com/yetpupyz
</a>Do: use clear descriptive link text
<a href="https://tinyurl.com/yetpupyz">
How to test with screen readers
</a>Though linked URLs are not necessarily a WCAG failure under 2.4.4 Link Purpose (In Context)(Level A) or 2.4.9 Link Purpose (Link Only)(Level AAA), if they are human-readable, it's rarely the clearest option.
Clear, descriptive link text reassures people about where the link leads and why it is there.
Non-text links
When icons, images, and other non-textual elements are linked, there are extra considerations to ensure the link remains accessible.
Icon links with visible text
Icons included within a link, in addition to visible link text, are typically decorative. In these cases, the icon should be hidden from assistive technology to avoid unnecessary noise. How the icon is added will determine how best to hide it.
Inline images using <img> can use an empty alt attribute to tell assistive technology to ignore the image:
<a href="...">
<img src="facebook-icon.png" alt />
Facebook
</a>
Many icon font libraries, like Font-Awesome, use CSS pseudo-elements to display the icon. Typically, these are ignored by assistive technology, but to be safe, you can add aria-hidden="true" to the element providing the icon. This prevents some screen readers, like VoiceOver, from displaying the icon as a question mark in a rectangle (⍰), which could be confusing to sighted screen reader users.
<a href="...">
<span class="fa-brands fa-facebook" aria-hidden="true"></span>
Facebook
</a>
In the example above, the visible text provides the accessible name. The icon is purely decorative.
Icon links without visible text
Sometimes an icon is the only visible content inside a link. Social media links in footers are a common example. These links can be harder for speech recognition software users to activate, as it's not obvious what they should say to activate the link. Typically, someone using speech recognition software will say "click", followed by the visible text label. In the case of icon only links, there is no visible text label, so they have to use additional steps to activate the link. For this reason, it's worth avoiding icon-only links.
If they are used, you must provide an accessible name for the icon link.
One approach is to include visually hidden text inside the link:
<a href="...">
<span class="fa-brands fa-facebook" aria-hidden="true"></span>
<span class="visually-hidden">Facebook</span>
</a>
The hidden text becomes the link’s accessible name and what's announced by screen readers.
Make sure the text is hidden visually but not from assistive technology. Do not use display: none or visibility: hidden, as these hide content from assistive technology.
The common visually hidden pattern uses the "clip method" and typically looks like:
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
The Vispero team did a great job of breaking this down in their post the anatony of visually-hidden.
Avoid using aria-label on the link, as Adrian Roselli notes - there are concerns around aria labels and translations.
Linked images
When an image is the only content inside a link, its alt text becomes the link’s accessible name and must be provided. It does the job that visible link text would normally do. Because of that, don’t describe what the image looks like. Use the alt text to describe the link’s destination or purpose.
The alt text is also shown if the image fails to load, so it needs to make sense as visible link text. For example:

The same principles apply as with any other link. Write a clear, specific label that explains the destination of the link.
If a linked image has no alt text, the screen reader experience is poor. Some screen readers will just announce "link". Others may attempt to read the file name or URL. Neither is helpful.
Don't: describe the image in the alt text
<a href="...">
<img src="passport.png" alt="A blue british passport">
</a>
Example screen reader output: "link, image, a blue British passport".
Do: use alt text to label the link
<a href="...">
<img src="passport.png" alt="Apply for a passport">
</a>
Example screen reader output: "link, image, apply for a passport".
Link behaviour
Avoid opening links in new tabs (warn users if you do)
Opening a link in a new tab can be disorientating for some users as it changes browsing context without warning. In most cases, leave the control with the user and let them decide whether to open the link in a new tab.
There are some situations where it may add value, for example:
- The link opens context-sensitive help that supports the current task.
- The user is working in a secure or form-based flow, and navigating away would risk losing data.
If there is a clear reason to open a new tab, warn the user in the link text.
Don't: open links in new tabs unnecessarily
<a href="https://www.facebook.com" target="_blank">
Follow us on Facebook
</a>Do: warn users when a link needs to open in a new tab
<a href="https://www.somewebpage.com/help" target="_blank">
View detailed instructions (opens in new tab)
</a>If you have a group of links that all open in new tabs, you can reduce repetition by:
- Adding a short note before the group, such as “The following links open in a new tab”, and
- Including visually hidden warning text inside each link for screen reader users.
WCAG techniques G200: Opening new windows and tabs from a link only when necessary and G201: Giving users advanced warning when opening a new window cover this pattern: only open new windows when necessary, and provide advance warning.
It’s also worth remembering that target="_blank" has security and privacy implications. If you use it, make sure it’s implemented safely.
Disabling links
In almost all cases, it's best to avoid disabling links.
It's an unusual, rarely seen pattern. HTML does not support the disabled attribute on <a>. Users expect links to be interactive. Disabling a link will likely lead to confusion. In cases where you think there is a need to disable a link, it's arguably better to remove the link completely or display it as plain text.
If, for some reason, you must disable a link (ignoring that it's probably a bad idea), then you need to make sure the disabled state is visually conveyed to the user and programatically conveyed to assistive technologies. Depending on the use case, it may be beneficial to explain why the link is disabled.
Remember at the start of this post, I mentioned that a link without a href is a placeholder link? That is essentially what we need, but with some added ARIA.
<a role="link" aria-disabled="true">Disabled link</a>
This approach:
- Removes the
href, so the link can't be focused or activated. - Explicitly sets the "link" role, as without the
hrefits role changes from "link" to "generic" and is therefore not announced as a link to screen readers. - Conveys the disabled state to assistive technologies via
aria-disabled="true"
Without an href, the element will not be keyboard focusable, but it can still be discovered by screen readers. That behaviour is consistent with other disabled elements, such as buttons and form inputs.
Scott O'Hara does a great job of going into more detail on this approach in disabling a link.
Styling considerations
Visually differentiate text links
It should be obvious when text is a link, either through its position, such as in a navigation menu, or through its visual styling.
By default, links are blue and underlined. Many sites change this to match their branding or design ideals, which is fine. The problems start when links are styled to look like normal body text, or when colour alone is used to distinguish them, especially when they're surrounded by plain text.
Not everyone can reliably perceive colour differences. People with low vision or colour vision deficiency may struggle to spot a link if colour is the only visual cue, especially when it sits within a paragraph of text.
Don't: rely on colour alone
I've written a guide on how to test with a screen reader, which goes into more detail.
Do: use a secondary visual cue
I've written a guide on how to test with a screen reader, which goes into more detail.
To make links easy to recognise, use an additional, consistent, visual cue to distinguish them from plain text. An underline is the most common and widely understood option, though other approaches work if they are consistent and clearly distinguish links from surrounding text.
While a link using colour alone to differentiate itself from plain text may not fail WCAG 1.4.1 Use of Color (Level A) if it contrasts with plain text by at least a 3:1 ratio, or even uses the same colour as the surrounding plain text, using colour alone to differentiate links should be avoided.
Text contrast rules apply
As with unlinked text, text contrast ratio requirements still apply. Aim for a 7:1 or greater contrast ratio where possible, which meets the requirements of WCAG 1.4.6 Contrast (Enhanced) (Level AAA), or at minimum, a 4.5:1 as required by WCAG 1.4.3 Contrast (Minimum) (Level AA).
Use a highly visible focus indicator
Focus indicators are critical for keyboard users. They highlight which element currently has keyboard focus and will therefore receive keyboard input. By default, browsers display some form of focus indicator, often a blue outline. While these have got better in recent years, they can still be hard to see in certain situations.
Crafting your own, highly visible focus indicator is strongly recommended. If you tab through this site, you'll see that I use a 3px solid outline and a yellow background colour when elements are focused, which contrasts on both light and dark backgrounds, and also meets the requirements of WCAG 2.4.13 Focus Appearance (Level AAA).
Don't: disable focus indicators
:focus,
:focus-visible { outline: none; }
By disabling focus indicators, the user is left guessing as to which element has keyboard focus and will receive keyboard input.
Do: use a highly visible focus indicator

There are many ways to create great looking, accessible focus indicators - Sara Soueidan does a great job of exploring this further in a guide to designing accessible, WCAG-conformant focus indicators.
Related WCAG success criteria:
- 1.4.11 Non-text Contrast (Level AA): details contrast requirements for focus indicators
- 2.4.7 Focus Visible (Level AA): requires a visible focus indicator to be present
- 2.4.13 Focus Appearance (Level AAA): contains enhanced requirements around sizing and contrast
- 2.4.11 Focus Not Obscured (Minimum) (Level AA): requires focused elements to be at least partially visible
- 2.4.12 Focus Not Obscured (Enhanced) (Level AAA): require focused elements to be fully visible
Make links large enough to comfortably activate
Not everyone uses a mouse with steady hands at a desk. Some people use a small phone with one hand. Some use a trackpad that is less precise. Others live with tremors, arthritis, or reduced motor control. Even a temporary injury or bumpy bus journey can make small targets hard to hit. If links are too small or packed tightly together, activating the right one can be difficult.
- Ideal size: Apart from links in sentences, aim for the target area of links to be at least 44px by 44px - which meets 2.5.5 Target Size (Enhanced) (Level AAA)
- Minimum size: If 44px by 44px sizing isn't possible, ensure a minimum of 24px by 24px - required by 2.5.8 Target Size (Minimum) (Level AA)
- Spacing: Leave enough space between nearby links to prevent accidentally activating the wrong link
While 2.5.8 Target Size (Minimum) (Level AA) does allow for smaller target sizes if they are adequately spaced, larger controls are easier to reliably activate.
Hover styles
- Style: It's a good idea to add styling that visually differentiates when a link is being hovered over. This could be increasing the width of the link underline, changing the background, or other visuals.
- Cursor: By default, browsers change the cursor pointer to a hand icon when hovering over a link. That's something users are familiar with, so I'd recommend against overriding it.
The link hover styles on this site increase the underline and keep the default link cursor:

Common patterns to avoid
These patterns introduce barriers for many different users, including those who use screen readers and speech recognition software.
Avoid pairing a heading with a generic link
A common pattern often seen on blog post list pages places a heading above some short text, followed by a link such as "Read more". For example:
<h2>Super cool blog post</h2>
<p>Some content</p>
<a href="/supercool-blog-post">Read more</a>
As mentioned above, link text should always describe the destination. Instead of rewording the link, we could remove it and link the heading text:
<h2><a href="/supercool-blog-post">Super cool blog post</a></h2>
<p>Some content</p>
This keeps the link text clear and avoids repeating information that already appears on the page.
Avoid linking an image and nearby text to the same place
Similar to the last pattern, listing pages often show an image next to a heading, with both linking to the same page. This results in two separate links that take the user to the same destination, two tab stops, and screen reader users hearing the link twice in close succession.
<a href="/making-links-accessible">
<img src="links.png" alt="Making links accessible">
</a>
<h2>
<a href="/making-links-accessible">Making links accessible</a>
</h2>
<p>Some content</p>
A simpler approach is to link the heading and unlink the image, adding alt text as appropriate (or leaving it empty to mark the image as decorative depending on the situation).
<img src="links.png" alt="Screenshot of links with poor link text">
<h2>
<a href="/making-links-accessible">Making links accessible</a>
</h2>
<p>Some content</p>
Don't use the same link text for different destinations
Good link text informs the user where the link will lead. When the same link text is used for different destinations, things become confusing and uncertain. For example:
<h1>Available courses</h1>
<h2>Art</h2>
<p>...</p>
<a href="/art">Explore courses</a>
<h2>Business</h2>
<p>...</p>
<a href="/business">Explore courses</a>
Screen reader users reading these links out of context may assume that they all lead to the same "explore courses" page, when they don't.
There are various approaches that could be taken here, depending on the content, such as supplementing the link with visually hidden text, linking and rewording the headings, or just improving the link text:
<h1>Available courses</h1>
<h2>Art</h2>
<p>...</p>
<a href="/art">Art courses</a>
<h2>Business</h2>
<p>...</p>
<a href="/business">Business courses</a>
Conclusion
If you made it this far, thank you! I appreciate that this is a long post. I did consider splitting it into a series of smaller posts, but keeping everything on one page felt more useful in this case.
Inaccessible links are still a common problem on the web. The 2025 WebAim Million report found that 13.7% of the top one million most popular homepages contained link-related accessibility issues.
Using semantic links and descriptive link text is a relatively easy way of making your web sites and applications more accessible. Much of the information in this post can also be applied to other mediums too - documents, emails, and social media.
