How to Fix Inaccessible Buttons and Clickable Divs
Buttons are everywhere on a website. They submit forms, open menus, close modals, apply filters, add products to carts, start trials, copy codes, toggle settings, and trigger checkout flows. When buttons are inaccessible, users can get stuck at exactly the moment they are trying to act.
A button accessibility issue usually happens for one of three reasons. The button is not a real button. The button does not have a clear accessible name. Or the button cannot be operated predictably with a keyboard and assistive technology. Each of these problems blocks a different group of users, and each has a different fix. The good news is that the underlying HTML platform already provides nearly everything you need. Most accessible buttons are accessible because the developer used the right element, not because they layered on a lot of extra code.
The most common version of the problem is the clickable div:
<div class="button" onclick="saveSettings()">Save settings</div>This may look like a button and work with a mouse, but it does not automatically behave like a button. It may not receive keyboard focus. It may not activate with Space or Enter. It may not communicate its role to assistive technology. It may not support disabled states correctly. The simplest fix is often to use a real <button> element.
<button type="button" class="button" onclick="saveSettings()">
Save settings
</button>ADA CodeFix flags button issues because they frequently block important tasks. This guide explains how to fix inaccessible buttons, clickable divs, icon buttons, toggle buttons, disabled states, loading states, and common ARIA mistakes you may have inherited from a previous developer or theme.
This page is informational and is not legal advice. Accessibility requirements can vary by site, organization, and jurisdiction. For legal guidance, consult qualified counsel. For accessibility conformance, combine automated scans with manual testing.
What makes a button accessible?
An accessible button should have:
- The correct semantic role
- A clear accessible name
- Keyboard focus
- Keyboard activation
- Visible focus styling
- A predictable disabled or loading state
- A clear relationship to any controlled content
- A role that matches what it actually does
Most of that comes for free when you use native HTML correctly.
<button type="button">
Open menu
</button>A real button announces itself as a button, can receive focus, can be activated by keyboard, and integrates with browser and assistive technology behavior. You do not need to add tabindex, you do not need to handle Enter and Space manually, and you do not need to wire up any ARIA role. The platform has already done that work.
Button vs link
A common accessibility problem is using buttons and links interchangeably. They look similar, especially when both are styled like pill-shaped CTAs, but they have different meanings and different behaviors in assistive technology.
Use a link when the user navigates to a new URL:
<a href="/pricing">View pricing</a>Use a button when the user performs an action on the current page:
<button type="button">Open pricing calculator</button>Use a submit button when submitting a form:
<button type="submit">Create account</button>Do not use a link with href="#" as a fake button:
<a href="#" onclick="openModal()">Open modal</a>Better:
<button type="button" onclick="openModal()">
Open modal
</button>This distinction helps users understand what will happen. Links go somewhere. Buttons do something. Screen reader users often navigate by lists of links or lists of buttons, so the right element makes the page easier to scan.
WCAG criteria related to buttons
WCAG 4.1.2 — Name, Role, Value
User interface components need a programmatically determinable name, role, and value. A button should be exposed as a button, have a meaningful name, and communicate state when applicable. A clickable div usually fails this criterion because it does not expose the button role to assistive technology.
WCAG 2.1.1 — Keyboard
Buttons should be operable through the keyboard. A user should not need a mouse to activate a button. If a button can only be triggered with a click event on a non-focusable element, it is unreachable for keyboard-only users.
WCAG 2.4.7 — Focus Visible
Keyboard users need to see when a button has focus. Removing the default focus ring without providing a replacement is one of the most common ways a button becomes inaccessible.
Common button accessibility failures
Failure 1: Clickable divs
Problem:
<div class="cta" onclick="startTrial()">
Start free scan
</div>Better:
<button type="button" class="cta" onclick="startTrial()">
Start free scan
</button>If you use a real button, you do not need to recreate native keyboard behavior. The platform handles focus order, activation, and role exposure for you.
Failure 2: Icon-only buttons without names
Icon-only buttons are common in modern interfaces. A button with only an SVG does not automatically have a useful name, because an SVG is not announced as text by default.
Problem:
<button type="button">
<svg aria-hidden="true" focusable="false">...</svg>
</button>A screen reader may announce this as "button" with no name, leaving the user with no idea what the button does.
Better:
<button type="button" aria-label="Open navigation menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>Or with visible text:
<button type="button">
<svg aria-hidden="true" focusable="false">...</svg>
Open menu
</button>Visible text is usually better when space allows. It helps users with cognitive disabilities, users on touch devices, and anyone who cannot interpret the icon at a glance.
Failure 3: Buttons with vague names
Problem:
<button type="button">Click here</button>Better:
<button type="button">Start accessibility scan</button>The button name should describe the action. When a screen reader user pulls up a list of buttons on the page, the names should make sense on their own, without surrounding context.
For repeated buttons, add context:
<button type="button" aria-label="Remove Basic plan from cart">
Remove
</button>If there are multiple "Remove" buttons, each one should be distinguishable to assistive technology users.
Failure 4: Missing type attribute
Inside a form, a <button> defaults to type="submit" in HTML. This can cause accidental form submissions when a user activates an unrelated button such as a help toggle.
Problem:
<form>
<button onclick="openHelp()">Help</button>
<button>Submit</button>
</form>Better:
<form>
<button type="button" onclick="openHelp()">Help</button>
<button type="submit">Submit</button>
</form>Always specify button type. It is one of the easiest defensive habits to adopt and prevents a class of bugs that are otherwise hard to reproduce.
Failure 5: Disabled buttons without explanation
Disabled buttons can be frustrating if the user does not know what is required to enable them.
Problem:
<button type="submit" disabled>
Continue
</button>Better:
<button type="submit" disabled aria-describedby="continue-help">
Continue
</button>
<p id="continue-help">
Enter your email address and accept the terms to continue.
</p>In some cases, it may be better to leave the button enabled and show validation errors after submission. That lets users discover what needs to be fixed instead of guessing why a button is unresponsive.
Failure 6: Loading buttons that change name badly
A loading state should communicate progress without making the button confusing.
Problem:
<button type="submit">...</button>Better:
<button type="submit" aria-busy="true" disabled>
Creating account...
</button>Or:
<button type="submit" disabled>
<span aria-hidden="true" class="spinner"></span>
<span>Creating account...</span>
</button>Avoid replacing the button name with only a spinner. A spinner on its own does not tell a screen reader user what is happening.
Toggle buttons
A toggle button has an on/off state. Use aria-pressed so assistive technology can announce the current state.
<button type="button" aria-pressed="false">
Bold
</button>When selected:
<button type="button" aria-pressed="true">
Bold
</button>For a favorite button:
<button type="button" aria-pressed="false" aria-label="Add listing to favorites">
<svg aria-hidden="true" focusable="false">...</svg>
</button>When active:
<button type="button" aria-pressed="true" aria-label="Remove listing from favorites">
<svg aria-hidden="true" focusable="false">...</svg>
</button>The label should make sense for the current action. The state should also be communicated. Together, the label and the pressed state give the user both the meaning and the status of the control.
Buttons that open menus
A button that opens or closes content should use aria-expanded and usually aria-controls.
<button
type="button"
aria-expanded="false"
aria-controls="main-menu"
>
Menu
</button>
<nav id="main-menu" hidden>
<a href="/features">Features</a>
<a href="/pricing">Pricing</a>
</nav>When opened:
<button
type="button"
aria-expanded="true"
aria-controls="main-menu"
>
Menu
</button>aria-expanded communicates whether the controlled content is open. Update it whenever the menu state changes, so screen reader users always hear the correct status.
Buttons that close modals
Close buttons are often icon-only. They need accessible names.
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" focusable="false">...</svg>
</button>Do not rely only on an "X" character unless it has a clear accessible name. The visual glyph alone is not always announced in a way users can rely on.
A visible text version is also fine:
<button type="button">
Close
</button>Styling buttons without breaking accessibility
A real button can be styled almost any way you want. You do not have to choose between brand design and accessibility.
.button {
appearance: none;
border: 0;
border-radius: 0.5rem;
padding: 0.75rem 1rem;
font: inherit;
cursor: pointer;
background: #1d4ed8;
color: #ffffff;
}
.button:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
.button:disabled {
cursor: not-allowed;
opacity: 0.65;
}Be careful with appearance: none; it removes browser styling but does not remove semantics. You still need to provide visible focus and disabled styles.
Do not remove focus outlines without replacing them:
button:focus {
outline: none;
}If you do remove the default, add a strong :focus-visible replacement so keyboard users can still see where they are on the page.
ARIA button role: when to avoid it
You can technically create a custom button with ARIA:
<div role="button" tabindex="0">
Save settings
</div>But then you must also recreate keyboard behavior, including activation with Enter and Space.
const customButton = document.querySelector('[role="button"]');
customButton.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
customButton.click();
}
});In most cases, this is unnecessary. Use a real button instead. ARIA should not be used to cover up avoidable HTML mistakes. Native controls are more reliable, easier to maintain, and better supported across browsers and assistive technology.
How ADA CodeFix detects button issues
ADA CodeFix can flag common button accessibility problems such as:
- Clickable non-interactive elements
- Buttons without accessible names
- Icon-only buttons without labels
- Buttons with vague text
- Links used as fake buttons
- Missing button
typeattributes - Buttons with weak or missing focus styles
- Toggle buttons missing state
- Menu buttons missing
aria-expanded - Disabled buttons that may need explanation
Some issues require human judgment. A scanner can identify a button named "More," but a developer may need to decide whether the surrounding context makes the action clear enough.
Manual button accessibility checklist
Use this checklist after making changes.
- Is the control a real
<button>if it performs an action? - Is the control a real
<a>if it navigates to a URL? - Does every button have a clear accessible name?
- Do icon-only buttons have
aria-labelor visible text? - Are repeated buttons distinguishable?
- Does every button inside a form have an explicit
type? - Can buttons be reached with the keyboard?
- Can buttons be activated with keyboard commands?
- Is focus visible on every button?
- Do toggle buttons communicate state?
- Do menu buttons communicate expanded/collapsed state?
- Are disabled or loading states understandable?
- Does a modal close button return users to a logical place?
Running through this list with a keyboard and a screen reader catches issues that automated tools miss. Pay particular attention to states that change, such as a menu toggle or a loading submit button.
Common mistakes to avoid
Mistake 1: Styling divs as buttons
If it looks and acts like a button, make it a button. Designers sometimes reach for div elements because they want full styling control, but every modern browser allows you to style a real <button> however you like.
Mistake 2: Hiding button text visually without providing a name
Icon-only buttons are fine only when they have accessible names. Hiding text with display: none generally removes it from the accessibility tree, which leaves the button without a name.
Mistake 3: Using aria-label to override useful visible text
If the visible button says "Delete account" but aria-label says "Submit," assistive technology users get misleading information. Voice-control users may also struggle because they often say the visible text. Make names accurate.
Mistake 4: Making disabled buttons the only source of instructions
If the user cannot proceed, explain why. A grayed-out button with no message leaves the user guessing.
Mistake 5: Forgetting focus styles
A button that works by keyboard still needs visible focus. Test with the keyboard alone and confirm that the focus ring is clearly visible against every background where the button can appear.
Platform-specific notes
WordPress
Check buttons created by themes, page builders, forms, sliders, and popup plugins. Some page builders create clickable containers instead of semantic buttons, which can pass a visual review while still failing keyboard testing.
Shopify
Review add-to-cart buttons, variant selectors, cart drawer buttons, quantity controls, discount-code controls, and menu toggles. Icon buttons for cart and search need accessible names so screen reader users can shop without guessing.
Webflow
Custom-styled div blocks are sometimes used as buttons. Confirm action controls are actual buttons or links with correct semantics. Webflow makes it easy to add either, so there is usually no design reason to substitute a div.
React and Next.js
Create reusable button components that default to safe behavior.
function Button({ type = "button", children, ...props }) {
return (
<button
type={type}
className="button"
{...props}
>
{children}
</button>
);
}For icon buttons:
function IconButton({ label, children, ...props }) {
return (
<button type="button" aria-label={label} {...props}>
{children}
</button>
);
}Do not allow icon buttons without labels. Treat the label prop as required so a missing accessible name becomes a build-time problem rather than something users discover after launch.
Final takeaway
Buttons are small elements with big consequences. If a user cannot activate a button, they may not be able to submit a form, open a menu, complete checkout, or start a scan. That single blocked interaction can prevent the rest of the page from mattering at all.
The safest fix is usually simple: use a real <button> for actions, use a real <a> for navigation, give every button a clear name, make focus visible, and test with the keyboard. ADA CodeFix can help identify common button problems and suggest developer-reviewable fixes, but important user flows should always be tested manually with a keyboard and a screen reader before you ship.
Sources
- W3C WCAG Understanding 4.1.2 Name, Role, Value (opens in new tab)
- W3C WCAG Understanding 2.1.1 Keyboard (opens in new tab)
- W3C WAI-ARIA Authoring Practices — Button Pattern (opens in new tab)
- MDN HTML button element (opens in new tab)
- W3C Web Accessibility Initiative (WAI) (opens in new tab)
Run a free WCAG 2.1 AA scan on your site
ADA CodeFix scans your pages, identifies likely WCAG failures, and generates developer-reviewable code fixes for buttons, focus styles, labels, alt text, color contrast, and more.
Scan My Site FreeRelated guides
Fix clickable divs, hover-only menus, and focus traps.
Focus-visible stylesBrand-friendly focus indicators that keep keyboard users oriented.
WCAG 4.1.2 Name, Role, ValueMake sure every control exposes its name, role, and state.
WCAG 2.1.1 KeyboardEnsure every button can be reached and activated by keyboard.