link
An interactive reference to an internal or external resource. Links are the fundamental navigation element of the web, allowing users to move between pages and resources.
Overview
The link role identifies an element as a hyperlink to an internal or external resource. When activated, the link navigates the user to the target resource, which could be a different page, a section within the current page, or an external website.
Important: Always use the native <a> element with an href attribute when possible. The role="link" should only be used when you absolutely cannot use an anchor element.
Links vs. Buttons
Links navigate to a resource (page, section, file). Use for navigation actions.
Buttons perform an action (submit, toggle, calculate). Use for in-page interactions that don't change the URL.
Live Demo: Link Interactions
Standard Links
Not visited yet
Opens in new tab
Link with States
"About" has aria-current="page"
Icon Links with Accessible Names
Try with keyboard: Tab to focus links, then press Enter to activate. Note that Space does NOT activate links (unlike buttons). Screen readers announce links with their accessible name and target information.
Code Examples
Basic Usage
<!-- Native anchor element (Best Practice) -->
<a href="/about">About Us</a>
<!-- Link with descriptive text -->
<a href="/pricing">View our pricing plans</a>
<!-- External link with indication -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
Visit Example.com
<span class="sr-only">(opens in new tab)</span>
</a>
<!-- AVOID: Using role="link" when <a> is available -->
<span role="link" tabindex="0">Don't do this</span>Custom Link Element
<!-- Custom link when <a> cannot be used -->
<span
role="link"
tabindex="0"
onclick="navigateTo('/page')"
onkeydown="handleLinkKeydown(event, '/page')"
class="custom-link"
>
Custom Navigation Link
</span>
<script>
function navigateTo(url) {
window.location.href = url;
}
function handleLinkKeydown(event, url) {
// Links activate on Enter only (not Space like buttons)
if (event.key === 'Enter') {
navigateTo(url);
}
}
</script>
<style>
.custom-link {
color: #0066cc;
text-decoration: underline;
cursor: pointer;
}
.custom-link:hover {
color: #004499;
}
.custom-link:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
</style>Descriptive Link Text
<!-- Good: Descriptive link text -->
<a href="/annual-report-2024.pdf">
Download the 2024 Annual Report (PDF, 2.4MB)
</a>
<!-- Good: Context from surrounding content -->
<p>
Learn more about our accessibility initiatives in our
<a href="/accessibility-statement">accessibility statement</a>.
</p>
<!-- Bad: Vague link text (avoid) -->
<a href="/page">Click here</a>
<a href="/docs">Read more</a>
<a href="/info">Learn more</a>
<!-- Better alternatives -->
<a href="/page">View product details</a>
<a href="/docs">Read the documentation</a>
<a href="/info">Learn about our services</a>Image & Icon Links
<!-- Image link with alt text as accessible name -->
<a href="/home">
<img src="/logo.png" alt="Company Name - Go to homepage">
</a>
<!-- Icon link with visually hidden text -->
<a href="/settings" class="icon-link">
<svg aria-hidden="true" class="icon">...</svg>
<span class="sr-only">Settings</span>
</a>
<!-- Image with separate link text -->
<a href="/product">
<img src="/product.jpg" alt="">
<span>View Product Details</span>
</a>
<!-- Screen reader only class -->
<style>
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>Link States
<!-- Current page indicator -->
<nav>
<a href="/home">Home</a>
<a href="/about" aria-current="page">About</a>
<a href="/contact">Contact</a>
</nav>
<!-- Disabled/non-interactive link -->
<a
href="/premium-feature"
aria-disabled="true"
tabindex="-1"
class="disabled-link"
>
Premium Feature (Upgrade Required)
</a>
<!-- Link with expanded state (disclosure) -->
<a
href="#section-content"
aria-expanded="false"
aria-controls="section-content"
onclick="toggleSection()"
>
Show More Details
</a>
<style>
.disabled-link {
color: #999;
pointer-events: none;
text-decoration: none;
}
</style>React Components
// React Link Components
import { useState } from 'react';
import Link from 'next/link'; // or react-router-dom
// Basic internal link
function InternalLink({ href, children }) {
return (
<Link
href={href}
className="text-blue-600 hover:text-blue-800 underline"
>
{children}
</Link>
);
}
// External link with new tab indicator
function ExternalLink({ href, children }) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-blue-800 underline inline-flex items-center gap-1"
>
{children}
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
<span className="sr-only">(opens in new tab)</span>
</a>
);
}
// Icon-only link with accessible name
function IconLink({ href, icon: Icon, label }) {
return (
<a
href={href}
aria-label={label}
className="p-2 rounded-lg hover:bg-gray-100 focus:ring-2 focus:ring-blue-500"
>
<Icon className="w-6 h-6" aria-hidden="true" />
</a>
);
}
// Download link
function DownloadLink({ href, fileName, fileSize }) {
return (
<a
href={href}
download={fileName}
className="inline-flex items-center gap-2 text-blue-600 hover:text-blue-800"
>
<span>Download {fileName}</span>
<span className="text-gray-500 text-sm">({fileSize})</span>
</a>
);
}
// Skip link for accessibility
function SkipLink() {
return (
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4
bg-blue-600 text-white px-4 py-2 rounded-lg z-50"
>
Skip to main content
</a>
);
}Keyboard Support
The only key that activates links. This is different from buttons which also respond to Space.
Links are included in the natural tab order. Ensure links have visible focus indicators.
Space Key Does NOT Activate Links
Unlike buttons, the Space key should NOT activate links. When implementingrole="link"on custom elements, only handle the Enter key. Space should scroll the page as expected.
Best Practices
Use native <a href="..."> element whenever possible
Provide descriptive, unique link text that makes sense out of context
Indicate when links open in new tabs (visually and for screen readers)
Use aria-current="page" for the current page in navigation
Ensure links have visible focus indicators (at least 3:1 contrast)
Provide file type and size for download links (e.g., "PDF, 2.4MB")
Don't use vague link text like "click here", "read more", or "learn more"
Don't use links for actions that don't navigate - use buttons instead
Don't remove underlines from links without providing another visual indicator
Don't use role="link" when you can use <a> with href attribute
Supported ARIA Attributes
aria-currentIndicates current item in a set (page, step, etc.)
aria-disabledIndicates link is not currently interactive
aria-expandedFor disclosure links that show/hide content
aria-labelProvides accessible name when text is not descriptive
aria-labelledbyReferences element(s) that label the link
aria-describedbyReferences element(s) that describe the link
aria-haspopupIndicates link triggers a popup (menu, dialog, etc.)
aria-controlsIdentifies element(s) the link controls
Common Use Cases
Accessibility Notes
Descriptive Link Text
Screen reader users often navigate by links alone, hearing a list of all links on the page. Link text should make sense out of context. Instead of "Click here to view pricing", use "View pricing plans". The link text itself should describe the destination.
External Links & New Windows
When links open in a new window or tab, inform users both visually (with an icon) and for screen readers (with visually hidden text like "opens in new tab"). This helps users understand they'll be navigating away and their context will change.
Visual Distinction
Links should be visually distinguishable from surrounding text. The default underline works well, but if you remove it, you must provide another indicator that doesn't rely on color alone (like font weight, border, or icon). WCAG requires 3:1 contrast between link and non-link text when not using underlines.
Skip Links
Provide a "Skip to main content" link as the first focusable element on the page. This allows keyboard users to bypass repetitive navigation. The link should be visually hidden until focused, then become visible.

