<button> vs <a>.
Navigation or action.
The two elements look similar, are often styled identically, and are used interchangeably in practice — which is a problem. They behave differently under the hood: how they're activated by keyboard, how they're announced by screen readers, how they support right-click "open in new tab." The rule is simple: <a> navigates to a URL, <button> triggers an action. Get it wrong and accessibility, SEO, and UX all suffer.
Short answer: Use <a href="..."> for navigation to a new URL. Use <button> for an action on the current page (submit, open a dialog, toggle a menu, delete). Don't use <a href="#"> for click handlers — that's a button pretending to be a link. Don't use <button onclick="location.href=..."> for navigation — that's a link pretending to be a button. Style is separate from semantics; a button can look like a link and vice versa.
✅ The rule
One question decides it: does clicking take the user somewhere?
Link = navigation
Clicking changes the URL. Home, about, product page, external site. Right-click "open in new tab" should work.
Button = action
Clicking triggers behavior on the current page. Submit, delete, toggle, open dialog. The URL doesn't change.
Keyboard differences
Links activate on Enter. Buttons activate on Enter and Space. Screen readers say "link" vs "button".
Style ≠ semantics
A link can look like a button (nav-styled CTAs). A button can look like a link (Cancel, Show more). Behavior follows the element.
✅ Before and after
The same UI, wrong and right.
<!-- ❌ Link pretending to be a button --> <a href="#" onclick="openDialog(); return false;"> Open settings </a> <!-- ❌ Button pretending to be a link --> <button onclick="location.href='/about'"> About us </button> <!-- ❌ Link with no href --> <a onclick="saveForm()">Save</a> <!-- ❌ Link with javascript: protocol --> <a href="javascript:void(0)" onclick="deleteItem()"> Delete </a>
❌ href="#" → URL gets #, back button breaks, right-click "open in new tab" opens the current page, screen reader says "link". ❌ Button navigation → right-click "open in new tab" missing, Ctrl+click missing, SEO can't crawl. Screen reader says "button" for a link. ❌ Link with no href → not keyboard focusable. Inaccessible. ❌ javascript: void(0) → deprecated, blocks CSP, breaks right-click, screen reader confusion.
<!-- ✅ Action → button --> <button type="button" onclick="openDialog()"> Open settings </button> <!-- ✅ Navigation → link --> <a href="/about"> About us </a> <!-- ✅ Form submit → button type="submit" --> <button type="submit">Save</button> <!-- ✅ Destructive action → button --> <button type="button" onclick="deleteItem()"> Delete </button>
✅ Button for actions: → Enter + Space activate it → Screen reader says "button" → Right-click doesn't show "open in new tab" (correct — it doesn't navigate) ✅ Link for navigation: → Enter activates it → Screen reader says "link" → Right-click shows "open in new tab" → Ctrl/Cmd+click opens in new tab → Search engines crawl the href The role matches the behavior. That's the whole rule.
✅ Style ≠ semantics
Style a button to look like a link, or a link to look like a button. Keep the element.
<!-- ✅ Button that looks like a link -->
<style>
.btn-link {
background: none;
border: none;
padding: 0;
color: #2563eb;
text-decoration: underline;
cursor: pointer;
font: inherit;
}
</style>
<button type="button" class="btn-link">Cancel</button>
<!-- ✅ Link that looks like a button -->
<style>
.btn {
display: inline-block;
padding: 0.5rem 1rem;
background: #2563eb;
color: white;
text-decoration: none;
border-radius: 4px;
}
</style>
<a href="/pricing" class="btn">See pricing</a>
Style is visual. Semantics are functional. "Cancel" opens a dialog → button, styled as link. "See pricing" navigates to /pricing → link, styled as button. Rule: pick the element based on behavior, then style it to match the design. Never pick the element based on appearance. The wrong element breaks keyboard, screen reader, right-click, SEO, and browser back button.
Don't use <a href="#"> for click handlers. This is the most common button-as-link mistake. It adds # to the URL (breaking the back button), announces as "link" to screen readers (misleading), and supports right-click "open in new tab" pointing at the current page. If the behavior is an action on the current page — open a dialog, toggle a menu, play a video — use <button type="button">. If you need the visual style of a link, use the .btn-link CSS pattern above. The element should match the behavior, always.
⚠️ Common mistakes
The button-vs-link mistakes that cost real time.
<a href="#"> for actionsBreaks back button, misleads screen readers. Fix: <button type="button">.
No right-click, no Ctrl+click, no SEO crawl. Fix: <a href>.
<a> with no hrefNot keyboard focusable. Fix: href for links, <button> for actions.
href="javascript:void(0)"Deprecated, breaks CSP. Fix: <button>.
Defaults to submit — accidental form submits. Fix: type="button" for non-submit.
ARIA can't change behavior. Fix: use the native element.
Not focusable, no keyboard events. Fix: <button> with CSS.
Keyboard users can't activate it. Fix: use <button> or <a href> — they handle keyboard for you.
❓ Frequently asked
What is the difference between a button and a link?
A link (a with href) navigates to a new URL. A button triggers an action on the current page — submit a form, open a dialog, toggle a menu, play a video. The distinction matters for keyboard users (Enter activates links, both Enter and Space activate buttons), for screen readers (announced as 'link' vs 'button'), for right-click users (open in new tab only works on links), and for search engines (links pass crawl equity). Use link for navigation, button for action.
Can I use a link styled as a button?
Yes — if the behavior is navigation. An 'Add to cart' that navigates to /cart is a link with a button style. A 'Submit order' that posts to an API is a button. The visual style is independent of the element. Style a link to look like a button — that is fine. But the behavior must match: if clicking navigates, it is a link. If clicking triggers an in-page action, it is a button. Style and semantics are separate concerns.
Can I use a button styled as a link?
Yes — if the behavior is an action. A 'Delete' button that shows a confirmation dialog should be a button with link-like styling (underlined text, no border, cursor pointer). A 'Log out' that calls an API and redirects is a button. The rule is the same: behavior first, style second. Screen readers, voice control, and keyboard users all rely on the role being correct. A button that looks like a link still behaves like a button — Enter activates, Space activates, no right-click open in new tab.
Why is href="Real URL" bad?
a href='#' navigates to the top of the page and adds a # to the URL, but does not trigger the JavaScript handler the way a button does. It also loses focus styles, breaks the browser's back button, and announces as 'link' when it's really a button. It is a link that lies about being a link. Fix: if the behavior is an action, use button. If it navigates, use href to the real URL. Never use href='#' for a click handler.
Does the button need type="button" inside a form?
Yes — unless it is the submit button. Inside a form element, a button with no type attribute defaults to type='submit' and will submit the form when clicked. If the button is meant to do something else — open a dialog, toggle a checkbox, cancel — add type='button' explicitly. The default is submit, which is a common source of accidental form submissions. Every button inside a form should have an explicit type: submit for the primary action, button for everything else.
How do I make a button look like a link?
Style the button: background: none; border: none; padding: 0; color: blue; text-decoration: underline; cursor: pointer; font: inherit;. This makes a button visually identical to a link. Keep the semantics: use button, not a. The button handles Enter, Space, focus styles, and screen reader announcements correctly. Only the visual style changes. Use this pattern for 'Cancel' buttons, 'Show more' toggles, and any destructive action that should look less prominent than the primary submit.