Accessible Links and Buttons — Complete Guide
In this tutorial, you will learn about Accessible Links and Buttons. We cover key concepts, practical examples, and best practices to help you master this topic.
Accessible links and buttons follow clear patterns: descriptive text that works out of context, proper semantic roles, visible focus indicators, full keyboard support, and visual styling that distinguishes them from surrounding text.
What You'll Learn
- The difference between links and buttons and when to use each
- How to write descriptive link text that works out of context
- Proper styling for links and buttons
- Keyboard expectations for interactive elements
- Common patterns: skip links, button groups, icon buttons
Why It Matters
- Links and buttons are the most commonly used interactive elements
- Non-descriptive links like "click here" fail WCAG Success Criterion 2.4.4
- Incorrect element choice (div as button, button as link) breaks Accessibility
- Screen reader users navigate by links — a list of "click here" entries is useless
Real-World Use
- A news article uses descriptive links: "Read the full climate report"
- A navigation uses proper button elements for menu toggle
- A form has clearly styled primary and secondary action buttons
- A page has a skip-to-content link as the first focusable element
flowchart LR
A[Interactive Element] --> B{Navigation or Action?}
B -->|Navigate to page| C[Use Link]
B -->|Perform action| D[Use Button]
C --> E[Descriptive href text]
D --> F[Clear action label]
E --> G[Underline or distinguish]
F --> H[Visible state changes]
Links vs Buttons
The fundamental question: does this element navigate somewhere or perform an action?
Links (<a href="...">) navigate to a new page or location within the current page. They have a URL destination. Screen readers announce them as "link."
Buttons (<button>) perform an action like submitting a form, opening a modal, or toggling a state. They do not navigate. Screen readers announce them as "button."
Mixing these up creates confusion:
- A "Search" element that navigates to results should be a link
- A "Search" element that expands a search form should be a button
- A "Submit" element that sends a form is always a button
Link Text Must Be Descriptive
Screen reader users can pull up a list of all links on a page. If every link says "click here" or "read more," the list is meaningless. Every link must make sense when read out of context.
<!-- Bad: context-dependent -->
<p>Our new report is available. <a href="/report">Click here</a> to read it.</p>
<!-- Good: descriptive -->
<p><a href="/report">Read the 2025 Accessibility Report</a> for our latest findings.</p>
<!-- Bad: vague -->
<a href="/products">Learn more</a>
<!-- Good: specific -->
<a href="/products">Browse our collection of handcrafted vases</a>
Code Example: Link Patterns
<!-- Standard text link -->
<a href="/products/laptops">View all laptops with 16GB RAM and SSD storage</a>
<!-- Link in a card/listing -->
<article>
<h2><a href="/blog/accessibility-tips">10 Web Accessibility Tips for Developers</a></h2>
<p>Practical advice for building inclusive websites.</p>
<a href="/blog/accessibility-tips" aria-label="Read more: 10 Web Accessibility Tips for Developers">
Read more
</a>
</article>
<!-- Link that opens in new window with warning -->
<a href="/pdf/report.pdf" target="_blank" rel="noopener noreferrer">
Download Report (PDF, opens in new window)
</a>
<!-- Link to skip navigation -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Link with icon (icon hidden) -->
<a href="/settings">
<svg aria-hidden="true" width="16" height="16"><path d="..."/></svg>
Account Settings
</a>
<!-- Link acting as a button (rare, only when necessary) -->
<a href="/" role="button" onclick="openMenu(event)">Menu</a>
<script>
function openMenu(event) {
event.preventDefault(); // Prevent navigation
// Open menu logic
}
</script>
Expected output: Each link is descriptive and makes sense in a link list. The skip link is the first focusable element. The PDF link warns users about the new window. Icon links include visible text.
Code Example: Button Patterns
<!-- Standard button -->
<button type="submit">Submit Order</button>
<!-- Button with aria-label for icon-only button -->
<button aria-label="Add to cart: Handcrafted Vase, $45.00">
<svg aria-hidden="true" width="24" height="24"><path d="..."/></svg>
</button>
<!-- Toggle button -->
<button aria-pressed="false" onclick="toggleMute(this)">
<svg aria-hidden="true" width="24" height="24"><path d="..."/></svg>
<span id="mute-label">Mute</span>
</button>
<script>
function toggleMute(button) {
const isPressed = button.getAttribute('aria-pressed') === 'true';
button.setAttribute('aria-pressed', !isPressed);
document.getElementById('mute-label').textContent = isPressed ? 'Mute' : 'Unmute';
}
</script>
<!-- Button group -->
<div role="group" aria-label="Text formatting">
<button aria-pressed="false">Bold</button>
<button aria-pressed="false">Italic</button>
<button aria-pressed="false">Underline</button>
</div>
<!-- Disabled button (with tooltip) -->
<button disabled aria-disabled="true" title="Sign in required to save">
Save for Later
</button>
Expected output: Buttons announce their purpose. Icon buttons have accessible names via aria-label. Toggle buttons announce their state. Disabled buttons indicate why they are disabled.
Code Example: Skip to Content Link
<style>
/* Skip link styling */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #0056B3;
color: white;
padding: 8px;
z-index: 100;
transition: top 0.1s;
}
.skip-link:focus {
top: 0;
outline: 3px solid #FFD700;
}
</style>
<body>
<!-- Skip link is the first focusable element -->
<a class="skip-link" href="#main-content">Skip to main content</a>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="main-content" tabindex="-1">
<h1>Main Content</h1>
<!-- ... -->
</main>
</body>
Expected output: When the page loads, the skip link is visually hidden but focusable. Pressing Tab on page load reveals it. Clicking or pressing Enter focuses on the main content area, skipping the navigation.
Common Mistakes
- Using "click here" as link text — This fails WCAG 2.4.4 because it provides no information about the link destination when read out of context.
- Opening links in new Windows without warning — Users may not notice the new window, and the back button no longer works as expected. Always warn about new windows.
- Using divs or spans as interactive elements — These are not focusable, not keyboard accessible, and not announced correctly by screen readers.
- Forgetting hover and focus styles — A link that only changes color on hover (not focus) gives keyboard users no feedback. Always pair hover and focus styles.
- Inconsistent link styling — Users expect links to be underlined (or otherwise visually distinct). Links that look like regular text are easily missed.
- Disabled buttons without explanation — A disabled button that does not explain why it is disabled frustrates users. Provide a tooltip or adjacent text.
- Same-page links without focus management — Anchor links that scroll to a section do not move focus. The user may be visually at the section but keyboard focus remains elsewhere.
Practice Questions
- When should you use a link versus a button? Use a link for navigation (going to a URL). Use a button for actions (submitting a form, opening a modal, toggling state).
- What is WCAG Success Criterion 2.4.4? Link Purpose (In Context): The purpose of each link must be determinable from the link text alone or from the link text together with its programmatically determined context.
- Why is "click here" bad for link text? Screen reader users can navigate by links. "Click here" provides no information about where the link goes.
- What is the purpose of a skip-to-content link? It allows keyboard users to skip past repeated navigation elements and jump directly to the main content.
- Challenge: Audit the links on a popular website (5 pages) and find at least 10 link text issues. Categorize them by issue type (vague text, opens new window without warning, no visible distinction, wrong element type). Propose fixes for each.
FAQ
{{< faq "Can a link open a modal dialog?" "Links should navigate. If you need to open a modal, use a button stylistically or use role="button" on the link with an event handler that prevents default navigation." >}}
Mini Project
Build an accessible card component library. Create 3 card variants: a product card (image, title, price, add to cart), an article card (image, category, title, excerpt, read more), and a profile card (avatar, name, title, contact button). Each card must use proper heading hierarchy, descriptive link text, ARIA labels where needed, visible focus indicators, and keyboard-accessible action buttons. Include a skip-to-content link. Test with keyboard only and a screen reader.
What's Next
Continue with Lesson 14: Accessible Forms to learn how to create forms that all users can understand and complete successfully.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro