Links and buttons can be styled to look identical, so it is tempting to treat them as interchangeable. They are not. They have different roles, different keyboard behaviour and different expectations, and screen reader users hear the difference.
The rule
- A link navigates. It takes the user to another page, another place on the same page, or a file. Use
<a href="...">. - A button performs an action. It submits a form, opens a dialog, toggles a menu, adds to a basket or plays a video. Use
<button>.
Ask: "Does the URL change, or could I open this in a new tab?" If yes, it is a link. If not, it is a button.
How they differ
Link (a href) | Button (button) | |
|---|---|---|
| Announced as | "link" | "button" |
| Activated by | Enter | Enter and Space |
| Browser features | Open in new tab, copy address, bookmark, visited state | None of these |
| Default in a form | No effect | Submits the form (unless type="button") |
| Listed in | The screen reader's links list | The form controls or buttons list |
Each mismatch causes a real problem. A screen reader user told "link" expects to go somewhere, and is confused when a dialog opens instead. A keyboard user presses Space on a link styled as a button, and the page scrolls instead.
Common mistakes and fixes
A link used as a button
<!-- Bad: no real destination, announced as a link -->
<a href="#" onclick="openFilters(); return false;">Filters</a>
<!-- Good -->
<button type="button" onclick="openFilters()">Filters</button>
href="#" and href="javascript:void(0)" are signs that a link should be a button.
A button used as a link
<!-- Bad: cannot be opened in a new tab or bookmarked -->
<button type="button" onclick="location.href = '/pricing'">See pricing</button>
<!-- Good: style the link to look like a button if the design needs it -->
<a class="button" href="/pricing">See pricing</a>
A clickable div
div and span have no role, are not focusable and ignore the keyboard.
<!-- Bad: mouse only -->
<div class="card-action" onclick="addToBasket(42)">Add to basket</div>
You could patch it:
<!-- Works, but needs all of this, and more for disabled states -->
<div class="card-action" role="button" tabindex="0" data-product="42">Add to basket</div>
<script>
const action = document.querySelector('.card-action');
const activate = () => addToBasket(Number(action.dataset.product));
action.addEventListener('click', activate);
action.addEventListener('keydown', (event) => {
if (event.key === 'Enter') activate();
if (event.key === ' ') event.preventDefault(); // stop the page scrolling
});
action.addEventListener('keyup', (event) => {
if (event.key === ' ') activate(); // native buttons activate Space on key up
});
</script>
Or you could write one line:
<button type="button" class="card-action" onclick="addToBasket(42)">Add to basket</button>
The native button also works with voice control, switch devices, forms, disabled and Windows contrast themes. Always replace the div.
Resetting button styles
The usual reason people avoid button is its default styling. Reset it once and reuse it.
.button-reset {
appearance: none;
margin: 0;
padding: 0;
border: 0;
background: none;
font: inherit;
color: inherit;
cursor: pointer;
}
Keep the focus outline: do not reset outline.
Write link text that makes sense
Screen reader users often list all links on a page and pick one. Ten links called "Read more" are useless in that list.
Success criterion 2.4.4 Link Purpose (In Context) (A) requires that each link's purpose can be determined from its text, or from its text together with its context, such as the sentence or list item it is in. 2.4.9 Link Purpose (Link Only) (AAA) asks for link text that makes sense entirely on its own, which is the better goal.
<!-- Weak -->
<p>Our refund policy changed in March. <a href="/refunds">Click here</a> to read it.</p>
<!-- Better -->
<p>Our <a href="/refunds">refund policy</a> changed in March.</p>
When a design needs short repeated link text, such as "Read more" on article cards, add hidden context:
<article>
<h3>Composting for beginners</h3>
<p>Turn kitchen waste into soil in eight weeks.</p>
<a href="/articles/composting">Read more<span class="visually-hidden"> about composting for beginners</span></a>
</article>
The visible text "Read more" is still at the start of the name, so it satisfies 2.5.3 Label in Name. The visually-hidden class is defined in lesson 8.
Other link text tips
- Avoid "click here" and "link to". Screen readers already say "link", and not everyone clicks.
- Warn when a link opens a new tab, downloads a file or goes to a different format: "Annual report (PDF, 2 MB)".
- Do not use the raw URL as link text unless people need to see it, such as on a printed page.
- Make links to the same destination use the same text, and links to different destinations use different text.
Opening new tabs
Opening links in new windows takes control away from users and confuses many screen reader and magnifier users. Avoid target="_blank" unless there is a strong reason, such as help content opened in the middle of a form. When you use it, say so in the link text.
<a href="/help/postcodes" target="_blank">Postcode help (opens in new tab)</a>
Summary
- Links navigate; buttons act. Choose by behaviour, not by appearance.
- Links respond to
Enter; buttons toEnterandSpace, and screen readers announce them differently. href="#"on an action is a button in disguise; abuttonthat changeslocationis a link in disguise.- Replace clickable
divandspanelements withbutton. - Write link text that makes sense out of context (2.4.4), and add hidden context to repeated "Read more" links.
- Avoid opening new tabs, and announce it when you must.