UX Design

Accessible Link and Button Design Patterns: Choosing the Right Element

By EZUD Published · Updated

Accessible Link and Button Design Patterns: Choosing the Right Element

Links and buttons are the two fundamental interactive elements on the web. They look similar, can be styled identically, and are often used interchangeably — but they have different semantics, different keyboard behaviors, and different expectations from assistive technology users. Using the wrong element creates confusion and breaks interaction patterns that users rely on.

Links navigate. They take the user to a new page, a new section of the current page, or a new resource (file download, external site).

Buttons perform actions. They submit forms, toggle UI states, open dialogs, delete items, or trigger any in-page functionality that does not navigate to a new URL.

This distinction matters because screen readers announce the element type, and users form expectations based on that announcement:

  • Hearing “link” → the user expects pressing Enter will navigate somewhere
  • Hearing “button” → the user expects pressing Enter or Space will perform an action

When a <button> navigates to a new page or a <a> triggers an in-page action, users become disoriented. Their expected behavior does not match reality.

Keyboard Behavior Differences

Behavior<a href> (Link)<button> (Button)
FocusFocusable by defaultFocusable by default
Activate with EnterYesYes
Activate with SpaceNo (scrolls page)Yes
Right-click context menuLink-specific (open in new tab, copy URL)Standard context menu
Middle-clickOpens in new tabNo effect
Browser historyAdds to historyNo history entry
Announce as”link""button”

When developers use <a href="#" onclick="doSomething()">, they create an element that announces as a link, has link context menus, but performs a button action. Space does not activate it (it scrolls the page instead). The interaction model is broken.

Avoid Generic Text

Screen reader users can navigate a page by listing all links. In this context, links are stripped of their surrounding text. A page full of “Click here” or “Read more” links becomes a list of identical, meaningless items.

Inaccessible:

<p>We published our annual report. <a href="/report">Click here</a> to read it.</p>

Accessible:

<p>Read our <a href="/report">2024 Annual Report</a>.</p>

The link text should communicate where the link goes or what the user will find:

  • “View our pricing plans” rather than “Learn more”
  • “Download the accessibility audit (PDF, 2.4 MB)” rather than “Download”
  • “Contact our support team” rather than “Click here”

If two links on the same page go to different destinations, they should have different link text. Two “Learn more” links — one for Product A and one for Product B — are indistinguishable when listed out of context.

When the visual design requires short, repeated link text (like “Read more” on a card grid), use aria-label or aria-labelledby to provide unique accessible names:

<article>
  <h3 id="article-title-1">Accessible Forms Guide</h3>
  <p>Learn to build forms that work for everyone...</p>
  <a href="/forms-guide" aria-labelledby="article-title-1 readmore-1">
    <span id="readmore-1">Read more</span>
  </a>
</article>

The screen reader announces: “Accessible Forms Guide, Read more, link.”

Button Patterns

Icon Buttons

Buttons with only an icon and no visible text must have an accessible name:

<button aria-label="Close dialog">
  <svg aria-hidden="true"><!-- X icon --></svg>
</button>

The aria-label provides the accessible name. The aria-hidden="true" on the SVG prevents screen readers from attempting to announce the SVG content.

Toggle Buttons

Buttons that toggle between states (mute/unmute, expand/collapse, play/pause) must communicate their current state:

<button aria-pressed="false">Mute</button>
<!-- When activated: -->
<button aria-pressed="true">Mute</button>

The aria-pressed attribute communicates the toggle state. Alternatively, update the button label to reflect the state:

<button>Mute notifications</button>
<!-- When activated: -->
<button>Unmute notifications</button>

Both approaches work. Choose consistently across your design system.

Sometimes design requirements call for a button styled as a link (underlined text, no background). The element should still be a <button> if it performs an action. Screen reader users will hear “button” regardless of visual styling, which is correct — the behavior matters more than the appearance.

Navigation elements styled as buttons (large, colorful call-to-action blocks) should remain <a> elements if they navigate. “Sign Up” that navigates to a registration page is a link, even if it is styled as a prominent button.

Focus Indicators

Both links and buttons must have visible focus indicators. The default browser outline works but can be enhanced:

a:focus-visible,
button:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}

Use :focus-visible rather than :focus to show focus indicators only for keyboard navigation, not mouse clicks. This addresses the common objection that focus outlines are “ugly” on click while maintaining keyboard accessibility.

WCAG 2.2 Success Criterion 2.4.7 (Focus Visible) requires visible focus at Level AA. Success Criterion 2.4.13 (Focus Appearance) at Level AAA specifies the minimum focus indicator area and contrast.

Common Anti-Patterns

<a onclick="doSomething()">Perform action</a>

Without href, the <a> element is not focusable by default, has no link role, and is not activated by Enter. If it is an action, use <button>. If it is navigation, add the href.

Div or Span as Interactive Element

<div class="link" onclick="navigate('/about')">About Us</div>

No role, no focus, no keyboard activation. See semantic HTML fundamentals for why native elements are essential.

target="_blank" opens links in new tabs, which can disorient users, especially screen reader users who may not realize the context has changed. If you must open in a new tab, warn users:

<a href="https://w3.org/wai" target="_blank" rel="noopener">
  W3C WAI (opens in new tab)
</a>

Wrapping an entire card — heading, image, text, and all — in a single <a> element causes screen readers to read the entire card content as the link name. Instead, use a heading link within the card and extend the click area with CSS:

.card {
  position: relative;
}
.card a::after {
  content: '';
  position: absolute;
  inset: 0;
}

This creates a full-card click area while keeping the link text concise.

  1. Tab through all interactive elements: Every link and button must receive focus with a visible indicator.
  2. Screen reader link list: List all links on the page. Each should have unique, descriptive text.
  3. Keyboard activation: Links activate with Enter. Buttons activate with Enter and Space.
  4. Right-click test: Links show “open in new tab” in context menu. Buttons do not.
  5. Validate with automated testing tools to catch missing labels and role issues.

Key Takeaways

Use <a> for navigation and <button> for actions — never the reverse. Write link text that describes the destination, not generic “click here.” Icon buttons need aria-label. Toggle buttons need aria-pressed or state-reflecting labels. Both need visible focus indicators. The link-or-button decision is a semantic choice, not a styling one — and assistive technology users depend on that choice being correct.