Button vs link: which one to use
Updated October 14, 2026 · 6 min read
"Button or link?" is the most common question in accessible front-end work, and the answer is short: a link takes you somewhere, a button does something. The visual style is a separate decision. This page shows the difference in code, keyboard and WCAG terms, and the mistakes we see most often on online shops. It is part of the accessible UI patterns series.
When to use which
Use a link <a href> |
Use a button <button> |
|---|---|
| Go to another page: product, category, cart page | Add to cart, change quantity |
Jump to a section on the same page (href="#reviews") |
Open or close a menu, dialog, filter panel |
| Download a file (invoice, size chart PDF) | Submit or reset a form |
| Open an external site | Play a video, start a slideshow, copy a code |
The APG puts it this way: "it is important that both the appearance and role of a widget match the function it provides". If something looks like a link but performs an action, the APG recommends changing its visual design rather than only giving it the button role.
Relevant WCAG criteria
- 4.1.2 Name, Role, Value (A): the role in the code must be correct, and every button and link needs a name.
- 2.1.1 Keyboard (A): both must work with the keyboard.
- 2.4.4 Link Purpose (In Context) (A): link text says where it goes; "click here" next to nothing does not.
- 2.4.7 Focus Visible (AA): both show focus.
- 2.5.3 Label in Name (A): the accessible name contains the visible text.
- 2.5.8 Target Size (Minimum) (AA): small icon buttons need 24 by 24 CSS pixels or enough spacing.
- 1.4.1 Use of Color (A): colour must not be the only thing that tells links inside text apart from the text around them.
Code example
<!-- Navigation: a link, even if it is styled as a button -->
<a href="/en/collections/sale" class="btn btn-primary">Shop the sale</a>
<!-- Action: a button. type="button" so it does not submit a surrounding form -->
<button type="button" class="btn" aria-describedby="price-123">Add to cart</button>
<!-- Icon-only button: the name comes from hidden text, the icon is hidden -->
<button type="button" class="icon-btn">
<svg aria-hidden="true" focusable="false"><use href="#icon-heart"></use></svg>
<span class="visually-hidden">Add to wishlist</span>
</button>
<!-- Toggle button: the name stays the same, the state changes -->
<button type="button" aria-pressed="false">Show prices with VAT</button>
Notes:
<a>withouthrefis not a link: it is not focusable and has no link role. If there is no URL, it is a button.href="#"orhref="javascript:void(0)"plus a click handler is a button pretending to be a link. Use<button>.- For a toggle button the APG says the label should not change with the state — "Mute" stays "Mute", and
aria-pressedtells whether it is on.
Keyboard interaction
| Key | Link | Button |
|---|---|---|
| Tab / Shift + Tab | Moves focus to and from it | Moves focus to and from it |
| Enter | Follows the link | Activates the button |
| Space | Not part of the link pattern; does not follow the link | Activates the button |
The APG button pattern lists Space and Enter for buttons; the link pattern lists Enter. Users rely on that difference. A link that only reacts to Space, or a "button" that only reacts to a mouse click, breaks expectations. When a button opens a dialog, focus should move into the dialog — see modal dialog.
Common mistakes on online shops
- Clickable
divandspanelements for "Add to cart", colour swatches or "Load more". They are invisible to the keyboard. - Whole product cards wrapped in a link that also contains buttons ("Add to wishlist" inside the card link). Interactive elements nested inside each other confuse browsers and assistive technology.
- Icon buttons without a name: cart, search, close (×), wishlist heart, quantity plus and minus.
- "Read more" and "Shop now" links repeated twenty times with no context, or the same text leading to different pages.
- Links in body text shown only by colour, often a brand colour close to the text colour.
- A
<button>inside a form withouttype="button", which submits the form when the user only wanted to open a size chart. - Tiny icon targets for quantity steppers and remove-from-cart.
What automated checks catch vs manual testing
Our rule library cards that cover this pattern:
| Automated (axe-core rule) | What it finds |
|---|---|
button-name, input-button-name |
Buttons without an accessible name |
link-name |
Links without an accessible name |
aria-command-name |
Elements with role="button" or role="link" without a name |
nested-interactive |
Buttons or links nested inside other interactive elements |
label-content-name-mismatch |
Visible text missing from the accessible name |
link-in-text-block |
Links in text that rely on colour alone |
target-size |
Targets smaller than 24 by 24 pixels without enough spacing |
identical-links-same-purpose |
Links with the same name that go to different places (advice) |
Manual testing is needed to decide whether an element should be a link or a button, to find clickable div elements that have no role at all, to check that Enter and Space behave correctly and that link texts make sense. Tab through the product page, the cart and the checkout and activate everything with the keyboard only.
Run the free one-page check on a product page to find the automated part. It is an automated check, not a full audit.
Frequently asked questions
When should I use a button and when a link?
Use a link (a element with href) when activating it takes the user to another page, another place on the page or a file. Use a button when it performs an action on the current page: add to cart, open a dialog, submit a form, toggle a filter.
Can a link look like a button?
Yes. WCAG does not regulate the visual style. What matters is that the element in the code matches what it does. A "Shop now" call to action that opens a category page is a link, even when it is styled as a button.
Why does it matter for screen reader users?
Screen readers announce the role ("link" or "button"), so users expect either navigation or an action. They also list links and buttons separately. A wrong role sets the wrong expectation.
Is a div with an onclick handler accessible?
Not by itself. It has no role, cannot be reached with Tab and does not react to Enter or Space. Use a real button or link instead.
Can an automated check tell a button from a link?
It finds buttons and links without a name and interactive elements nested inside each other. It cannot tell whether a link should really have been a button, and usually cannot see clickable div elements.
Sources
- W3C WAI, APG Button pattern: https://www.w3.org/WAI/ARIA/apg/patterns/button/
- W3C WAI, APG Link pattern: https://www.w3.org/WAI/ARIA/apg/patterns/link/
- W3C, Using ARIA (rules of ARIA use): https://www.w3.org/TR/using-aria/