Patterns Link vs button

Link vs button

Buttons do, links go. Picking the wrong one breaks keyboard model, screen-reader announcement, and right-click expectations all at once.

Reviewed against the methodology checklist Updated

Try the keyboard

The rule

Buttons do. Links go.

If activating the control performs an action on this page — submit a form, open a dialog, toggle a thing, copy text, save a draft — it’s a <button>. If activating it takes the user to a different URL — another page on this site, a section of the same page, an external resource — it’s an <a href>.

That’s it. There are no exceptions worth memorising.

The pattern

A button and a link, side by side

Button — performs an action

Link — goes somewhere

Browse all patterns

The two controls behave differently because the user has different expectations of each:

ButtonLink
Announced as”button""link”
Activated byEnter or SpaceEnter only
Right-click menu(none useful)“Open in new tab”, “Copy link address”
Browser historynot affectedadds a history entry
Visual defaultfilled chip with affordanceunderlined inline text

Use the wrong element and all of those expectations break at once. A “link” that runs JavaScript and stays on the page can’t be opened in a new tab. A “button” that navigates can’t be activated with Space. A screen reader announces the wrong role, so the user doesn’t know what’s about to happen.

HTML
<!-- Action: stays on this page, performs work -->
<button type="button">Save draft</button>

<!-- Navigation: goes somewhere -->
<a href="/patterns/">Browse all patterns</a>

Anti-patterns

HTML
<a href="#" onclick="saveDraft(); return false;">Save draft</a>

Three problems:

  1. Wrong role — screen readers announce “link”, users expect navigation.
  2. Right-click is broken — “Open in new tab” reloads the page with # appended; “Copy link address” returns garbage.
  3. History pollution — even with return false, some browsers add a history entry. Back button now requires extra presses.
HTML
<button type="button" onclick="location.href='/patterns/'">
Browse all patterns
</button>

The opposite mistake. Two problems:

  1. Wrong role — screen readers announce “button”, users don’t expect navigation.
  2. No right-click navigation tools — buttons don’t have “Copy link address” or “Open in new tab”.

If the visual design calls for a link-styled control that navigates, use a real <a href>. CSS doesn’t care what element it’s applied to.

Form button without type

HTML
<form>
<input type="text" name="email">
<button onclick="trackOpen()">Tell me more</button>  <!-- whoops -->
</form>

<button> defaults to type="submit" inside a form. The above button submits the form when clicked — even though the developer thought they were just running a tracking call. Always set type="button" on buttons that aren’t submitting.

Common situations

Checklist

Screen reader transcript

Voiced by George — reading what VoiceOver on macOS Safari announces. Other readers (NVDA, JAWS) phrase things differently; the meaning is what matters.

Screen reader announcements for each step
ListenYou doScreen reader says
Tab to the buttonSave draft, button.
Tab to the linkBrowse all patterns, link.

Screen reader transcript — anti-pattern

Same interaction, but on the broken version above. Notice what the user is missing.

Screen reader announcements for each step
ListenYou doScreen reader says
Tab to a "link" that should have been a buttonSave draft, link. (the user expects to navigate; they activate; nothing visibly happens; the page reloads with a # in the URL)

WCAG references