button
An input that allows for user-triggered actions. Buttons are clickable elements that trigger a response when activated by the user.
Overview
The button role identifies an element as a button to assistive technologies. When activated, it triggers an action such as submitting a form, opening a dialog, or performing a calculation.
Important: Always use the native <button> element when possible. The role="button" should only be used when you must use a different element due to styling or framework constraints.
Native <button> vs role="button"
The native <button> element provides keyboard support, focus management, and form integration automatically. Using role="button" requires you to manually implement all keyboard interactions.
Live Demo: Button Interactions
Native Button (Best Practice)
Toggle Button (aria-pressed)
Try with keyboard: Tab to focus the buttons, then press Enter or Space to activate them. Screen readers will announce these as buttons and their states.
Code Examples
Basic Usage
<!-- Basic Button with ARIA role -->
<div role="button" tabindex="0">
Click Me
</div>
<!-- Note: Use native <button> element when possible -->
<button>I'm better!</button>
<!-- Use role="button" only when semantic HTML isn't an option -->Keyboard Support
<!-- Accessible custom button with keyboard support -->
<div
role="button"
tabindex="0"
onclick="handleClick()"
onkeydown="handleKeyPress(event)"
>
Save Changes
</div>
<script>
function handleClick() {
console.log('Button clicked');
}
function handleKeyPress(event) {
// Support both Enter and Space keys
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault(); // Prevent page scroll on Space
handleClick();
}
}
</script>Disabled State
<!-- Disabled button with aria-disabled -->
<div
role="button"
tabindex="0"
aria-disabled="true"
onclick="if (this.getAttribute('aria-disabled') === 'true') return false;"
class="button-disabled"
>
Disabled Button
</div>
<style>
.button-disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
</style>Toggle Button (aria-pressed)
<!-- Toggle button with pressed state -->
<button
role="button"
aria-pressed="false"
onclick="toggleButton(this)"
>
<span class="icon" aria-hidden="true">๐</span>
Mute
</button>
<script>
function toggleButton(btn) {
const pressed = btn.getAttribute('aria-pressed') === 'true';
btn.setAttribute('aria-pressed', !pressed);
// Update visual state
const icon = btn.querySelector('.icon');
icon.textContent = !pressed ? '๐' : '๐';
btn.textContent = !pressed ? 'Unmute' : 'Mute';
}
</script>React Components
// React Button Component
import { useState } from 'react';
// Good: Use native button
function GoodButton({ onClick, children }) {
return (
<button
onClick={onClick}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
{children}
</button>
);
}
// Only when necessary: Custom button with role
function CustomButton({ onClick, disabled, children }) {
const handleKeyDown = (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
if (!disabled) onClick();
}
};
return (
<div
role="button"
tabIndex={disabled ? -1 : 0}
aria-disabled={disabled}
onClick={disabled ? undefined : onClick}
onKeyDown={handleKeyDown}
className={`px-4 py-2 rounded ${
disabled
? 'bg-gray-300 cursor-not-allowed'
: 'bg-blue-500 cursor-pointer'
}`}
>
{children}
</div>
);
}
// Toggle Button with aria-pressed
function ToggleButton() {
const [pressed, setPressed] = useState(false);
return (
<button
aria-pressed={pressed}
onClick={() => setPressed(!pressed)}
className={`px-4 py-2 ${pressed ? 'bg-blue-700' : 'bg-blue-500'}`}
>
{pressed ? 'On' : 'Off'}
</button>
);
}Keyboard Support
Must prevent default browser scroll behavior when implementing on custom elements.
This is the primary activation method for form submissions.
Best Practices
Use native <button> element whenever possible
Provide clear, descriptive button labels
Ensure buttons have visible focus indicators
Support both Enter and Space key activation
Use aria-pressed for toggle buttons
Use aria-disabled instead of removing from tab order when disabled
Don't use role="button" on <a> elements - use <button> instead
Don't use buttons for navigation - use links (<a>) instead
Don't forget to add tabindex="0" when using role="button" on divs
Don't rely only on color to indicate button state
Supported ARIA Attributes
aria-pressedToggle button state (true/false/mixed)
aria-expandedWhether controlled element is expanded
aria-haspopupIndicates button opens a popup/menu
aria-disabledIndicates button is disabled
aria-labelAccessible name for the button
aria-labelledbyReferences element(s) that label button
aria-describedbyReferences element(s) that describe button
aria-controlsIdentifies element(s) button controls
Common Use Cases
Accessibility Notes
Keyboard Navigation
When using role="button" on non-button elements, you must implement keyboard support manually. Handle both Enter and Space keys, and remember to prevent default Space key behavior to avoid page scrolling.
Focus Indicators
Always provide visible focus indicators for buttons. This helps keyboard users know where they are on the page. The default browser outline is acceptable, but custom styles should meet WCAG contrast requirements (3:1 minimum).
Screen Reader Announcements
Screen readers will announce the element as a "button" along with its accessible name. For toggle buttons, use aria-pressed to communicate the current state. Screen readers will announce "pressed" or "not pressed" along with the button name.

