Buttons vs links: which to use and why it matters

Use a link when activating the control takes you somewhere, such as another page, a file or a spot on the same page. Use a button when it does something where you are, such as submitting a form, opening a dialog or toggling a menu. The two expose different roles and keyboard behavior, so a link that works as a button, a button that works as a link or a clickable div can fail screen reader, keyboard and voice users.

Published . Last reviewed .

The working rule is short: a link goes somewhere, and a button does something. W3C's ARIA Authoring Practices Guide (APG) defines a link as an interactive reference to a resource inside or outside the current page (APG link pattern), and a button as a widget that triggers an action, such as submitting a form, opening a dialog, canceling or deleting (APG button pattern). Browsers and assistive technology announce different roles for the two, activate them on different keys and offer different extras, so choosing the wrong one, or building either from a div, takes behavior away from the people who depend on it.

The choice sits under a lot of other accessibility work. Success criterion 4.1.2 Name, Role, Value (Level A) asks that every interface component expose its name and role to software, and W3C's Understanding document for 4.1.2 names screen readers, screen magnifiers and speech recognition software as examples of the assistive technology it supports. Basic markup often goes wrong: in the February 2026 WebAIM Million, 46.3% of home pages had an empty link and 30.6% had an empty button. Those figures count unnamed controls, not wrong choices of element. This guide is part of our walkthrough of how to make a website accessible.

Which one should you use?

Ask what happens when someone activates the control. If it loads a different page, a file or a place, it is a link. If it changes something on the current page or sends data, it is a button. The test is behavior, not appearance. These examples cover most pages.

Common controls, the element that fits each and why
ControlUseWhy
Pricing, in the main navigationLinkIt goes to another page, which has its own address.
Skip to contentLinkIt points to a place on the same page, and a link can address one.
Download the 2026 price list (PDF)LinkIt points to a file.
Next page of resultsLinkEach page of results has its own address.
Place orderButtonIt sends form data.
Sign in, when it opens a dialogButtonOpening a dialog is an action. The same words on a control that opens a sign-in page make it a link.
Shipping details, an expandable sectionButton with aria-expandedIt shows and hides content in place.
MuteToggle button with aria-pressedIt switches a state on and off.
Export to CSV, built by a scriptButtonIt is an action, not a destination. A file that already exists at an address is a link.

Single-page apps blur the line, because script can swap the view without a page load. In GotAlt's reading, the question is still whether the address changes: a control that moves to a new route is navigation, so make it a real link. MDN's page on the a element says that, in general, a hyperlink should be used only for navigation to a real URL.

What a real link and a real button give you

The first choice is a native element, because native elements come with behavior. W3C's technique H91 explains that browsers provide keyboard operation for HTML form controls and links and map them to the accessibility API, so assistive technology can read their role, name, state and value. The 4.1.2 Understanding document adds that standard HTML controls already meet the criterion when used according to specification.

What the native link and button elements provide
BehaviorLink (a with href)Button (button)
Role announcedLinkButton
Keyboard focusIn the Tab orderIn the Tab order
Keys that activate itEnterEnter and Space
Screen reader shortcut (NVDA)K jumps to the next linkB jumps to the next button
Browser extrasOpen in a new tab, copy the address, bookmarkNone, because a button has no address
Inside a formDoes nothing to the formSubmits the form, unless type="button" is set
Unavailable stateNo native disabled state: an a with no href is not a linkThe disabled attribute: it cannot be pressed or focused

The roles come from the HTML Accessibility API Mappings, the keys from the APG patterns and MDN, and the NVDA shortcuts from WebAIM's NVDA guide. MDN's page on the button element describes the form behavior and the disabled attribute, and advises type="button" on any button that does not submit a form.

How fake buttons and fake links go wrong

A clickable div or span

A div or span has no role of its own, so when a script makes one act like a control and no role is added, assistive technology may have nothing to announce. W3C documents this as failure F59 of 4.1.2. Failure F42 covers links built this way: they cannot be tabbed to, assistive technology may not recognize them as links, and they do not appear in the list of links that browsers and assistive technology generate. F42 ties the missing role to 1.3.1 and 4.1.2, and the missing keyboard operation to 2.1.1 and 2.1.3. Here is a before and after:

<!-- Fails: no role, no Tab stop, no keyboard activation -->
<div class="btn" onclick="openFilters()">Filters</div>

<!-- Works: role, focus, Enter and Space are built in -->
<button type="button" onclick="openFilters()">Filters</button>

A div can be repaired with role="button", tabindex="0" and key handling. The APG's Read Me First page calls a role a promise: div role="button" promises that the author has written the keyboard interactions a button needs, because ARIA roles do not make browsers provide keyboard behavior or styling. For a button, that means activation on both Enter and Space. W3C's note on 2.1.1 Keyboard says a custom button that reacts only to Enter still meets that criterion, and calls following platform conventions a best practice. In GotAlt's reading, a native button keeps the promise for you. When a custom control is unavoidable, see ARIA basics and focus order and tabindex.

A link used as a button

Anchors are often misused as buttons by giving them href="#" or javascript:void(0) and listening for clicks. MDN says these values cause unexpected behavior when the link is copied or dragged, opened in a new tab or bookmarked, and when scripts are loading, failing or switched off. It adds that they convey incorrect semantics to assistive technology, and its advice is to use a button instead.

An a with no href at all is not a link. The HTML Standard calls it a placeholder for where a link might have been, and the HTML Accessibility API Mappings give it the generic role.

A button used as a link

The reverse mistake is a button whose click handler sets location.href to move to another page. The visitor hears a button rather than a link, and the control has no address to open in a new tab, copy or bookmark, which are the behaviors MDN lists as breaking with fake links. Use a href and let the browser navigate.

One inside the other

A button inside a link, or a link inside a button, is invalid HTML: the HTML Standard's content models for the a element and the button element allow no interactive content inside either. In GotAlt's reading, it also gives keyboard users two stops for one action. Choose one element and style it to suit the design.

A link that looks like a button, and the reverse

A link styled as a button is common for calls to action that lead to another page. In GotAlt's reading, that is fine as long as the element is a real link, because people still get the link role, an address and a place in the list of links. One detail applies: the APG lists only Enter as a link's activation key, so a link styled as a button will not respond to Space, which people may press because the control looks like a button.

The APG also notes that elements sometimes look like links but act as buttons. For such an element it advises giving it the button role, and it calls a better solution adjusting the visual design so that appearance, role and function agree. A native button styled as text already has the right role. The remaining concern is sighted visitors, who may read link-like text as navigation. In GotAlt's reading, style actions as actions. Whatever the style, both elements need a visible focus indicator (see focus indicators) and a target big enough to hit (see touch target size).

Buttons that hold state: toggles, disclosures and menus

Some buttons keep a state or control other content. Between its button and disclosure patterns, the APG describes three kinds, and each is still a button because none goes anywhere:

  • Toggle button. A two-state button marked with aria-pressed. The label must not change when the state changes, so a "Mute" button stays "Mute" while aria-pressed switches to true. If the design changes the label from "Mute" to "Unmute", aria-pressed is not needed.
  • Disclosure button. A button that shows and hides a section, with aria-expanded true while the content is visible, as in the APG disclosure pattern.
  • Menu button. A button with aria-haspopup set to menu or true.
<button type="button" aria-pressed="false">Mute</button>
<button type="button" aria-expanded="false">Shipping details</button>

The full patterns are in our guides to accessible accordions and tabs, accessible menus and accessible modals.

Names, focus and disabled controls

Names. Both elements take their name from their content by default, and both need one. The APG says a button's name comes from its text content, with aria-labelledby or aria-label as alternatives, and MDN notes that a button showing only an icon has no accessible name, and its fix is to put text inside the button. Link wording is covered in accessible link text and on the WCAG 2.4.4 page, and icons in alt text for icons.

Focus after activation. A link moves focus to its target, according to the APG. For a button, the APG says it depends on the action: opening a dialog moves focus inside it, closing one usually returns focus to the opening button, and an action such as Apply keeps focus on the button.

Disabled buttons. The HTML disabled attribute makes a button impossible to press or focus, and the APG uses aria-disabled="true" for a button whose action is unavailable. Because Tab skips a disabled button, a keyboard user may get no hint that a submit control exists or why it is unavailable. In GotAlt's reading, a clear message on submit is often kinder than a silent disabled state. See accessible forms.

Check it yourself

  1. Tab through the page. Every link and button should take focus and show where it is. Press Enter on links, and Enter and Space on buttons. A control that looks clickable and never takes focus is a candidate fake. The keyboard accessibility test sets out the full routine.
  2. Right-click the controls that go to another page. A real link offers browser options such as opening in a new tab or copying the address, though the menu varies by browser. A control that goes to a page and offers none may be built from something else.
  3. Listen for the role. In NVDA, K moves to the next link and B to the next button, and NVDA+F7 opens an Elements List of page links, headings and landmarks. A fake link is missing from the links list, as F42 describes. See how screen readers read a page.
  4. Search the markup. In your browser's developer tools, look for href="#", javascript:, onclick on a div or span, role="button" on an a, and a button inside a link.
  5. Run the link text checker. It lists every link with the name a screen reader would announce and its destination, and flags empty names, generic phrases, bare URLs and the same text pointing to different places. For this topic, the Destination column makes # and javascript: entries easy to spot, although the tool does not flag them itself. It lists only a elements that have an href, so a clickable div is outside it. To include links that scripts add, paste the page's HTML from your browser.
  6. Use the accessibility bookmarklet on the page as it renders, including pages behind a login. It reports links and buttons with no accessible name.
  7. Scan my site for free to run 16 rule-based checks, including links and buttons with no accessible name, on up to 3 pages.

None of these can decide whether a control should be a link or a button. That depends on what it does, so someone who knows the page needs to read through the list. Unnamed controls also sit among the most common accessibility errors, and WCAG 1.3.1 covers the wider rule that structure is available to software.

Keep it checked

A fixed control can break again with the next template change or new component. GotAlt checks the pages you monitor every week. It compares each image's alt text with the image itself (up to six images per page), runs its rule checks, opens monitored pages in a browser for contrast and other render-dependent checks (see what we check), and reports what changed. Plans are from $69 a month. Audit my whole site from $69/mo.

Buttons and links questions

Should I use a button or a link to open a dialog?

A button. The APG button pattern lists opening a dialog among the actions a button triggers, while a link is for reaching a resource. After the dialog opens, focus moves inside it, and closing it usually returns focus to the button that opened it.

Can I make a link look like a button?

Yes, if the element is a real link. A styled link keeps its link role, its address and its place in the list of links, and it still goes somewhere. The APG lists only Enter for links, so it will not respond to Space the way a button does. Make the visible text name the destination, as in "Compare plans".

Is href="#" acceptable on a link that runs JavaScript?

No. MDN says such links misbehave when copied, opened in a new tab or bookmarked, and when scripts fail, and that they convey incorrect semantics to assistive technology. Use a button with type="button" for the action, and keep links for real destinations.

Why does a button respond to the Space key when a link does not?

The two follow different keyboard conventions. The APG says Space and Enter both activate a button, and it lists only Enter for a link. A native button and a native link get these keys from the browser. A div with a role gets neither unless a script supplies them.

Is a div with role="button" accessible?

Only if the author does the rest of the work. The APG's Read Me First page says a role is a promise, and that ARIA roles do not make browsers provide keyboard behavior or styling. The div needs focus and activation on Enter and Space. A native button provides all of that with no script.

Does using the wrong element fail WCAG?

It can. W3C documents scripted fake links and fake controls as failures of 4.1.2, with 1.3.1, 2.1.1 and 2.1.3 also named for links (F42, F59). No criterion is titled "use a button for actions", and an a href="#" is not named in those failures. In GotAlt's reading, fix it anyway.

Should a download be a button or a link?

A link, when it points to a file that exists at an address, because MDN lists files among the things a hyperlink can address. A control that generates the file with a script, such as an export, is an action, so a button fits. Name the file type either way, as in "Price list (PDF)".

Find the unnamed links and buttons on your site

The free scan flags links and buttons with no accessible name across up to 3 pages, among 16 rule-based checks. It cannot tell whether a control should be a link or a button, so use the steps above for that. No signup.

Scan my site for free