aria-disabled
Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. Unlike the HTML disabled attribute, aria-disabled elements remain focusable.
Overview
The aria-disabled attribute indicates that an element is perceivable but disabled, meaning it is not editable or otherwise operable. It communicates the disabled state to assistive technologies without removing the element from the accessibility tree.
Unlike the native HTML disabled attribute, elements with aria-disabled="true" remain in the tab order and can receive focus. This is useful when you want users to be able to discover disabled controls and understand why they are unavailable.
Important: Prevent Interaction in JavaScript
aria-disabled only affects the accessibility tree—it does NOT prevent clicks or keyboard activation. You must add JavaScript to prevent the action when the element is disabled.
Live Demo: aria-disabled in Action
Form with Conditional Submit
Please accept the terms to continue
Button has aria-disabled="true" — Note that it's still focusable!
Native disabled (unfocusable)
Try to tab to this — you can't!
aria-disabled (focusable)
Try to tab to this — you can!
Screen reader announcement: Both buttons will announce as "disabled". However, with aria-disabled, users can still focus the button and discover it exists. Screen readers announce: "Create Account, disabled, button".
disabled vs aria-disabled
disabled(HTML attribute)
- • Prevents all interaction (click, focus)
- • Removes element from tab order
- • Browser provides default styling
- • Works on form elements only
- • No JavaScript needed to block clicks
Use when: Element should be completely non-interactive and doesn't need to be discovered by keyboard users.
aria-disabled="true"(ARIA attribute)
- • Announces "disabled" state only
- • Element remains in tab order
- • Must style disabled state yourself
- • Works on any element
- • Must prevent clicks in JavaScript
Use when: Users need to discover the control exists, or you want to provide an explanation of why it's disabled.
Code Examples
Basic Usage
<!-- aria-disabled vs disabled attribute -->
<!-- Native HTML disabled (preferred for form elements) -->
<button disabled>Submit</button>
<input type="text" disabled value="Cannot edit" />
<!-- aria-disabled (for custom widgets or when you need focus) -->
<div
role="button"
aria-disabled="true"
tabindex="0"
>
Custom Button
</div>
<!-- Key difference: aria-disabled still allows focus! -->disabled vs aria-disabled
<!-- IMPORTANT: disabled vs aria-disabled -->
<!-- disabled attribute -->
<button disabled>Submit</button>
<!--
• Prevents click AND focus
• Removes from tab order
• Browser handles styling (:disabled)
• Cannot receive keyboard events
-->
<!-- aria-disabled="true" -->
<button aria-disabled="true">Submit</button>
<!--
• Announces "disabled" to screen readers
• Still focusable (stays in tab order)
• Click events still fire (must prevent in JS)
• Allows explaining why it's disabled
-->
<!-- When to use aria-disabled over disabled: -->
<!-- 1. Custom widgets (divs with role="button") -->
<!-- 2. When disabled item needs to remain focusable -->
<!-- 3. To explain why something is disabled -->Form with Conditional Submit
<!-- Form with conditional submit button -->
<form>
<label for="email">Email address</label>
<input type="email" id="email" required />
<label for="terms">
<input type="checkbox" id="terms" required />
I accept the terms and conditions
</label>
<!-- Button enabled only when terms accepted -->
<button
type="submit"
aria-disabled="false"
aria-describedby="submit-help"
>
Create Account
</button>
<span id="submit-help" class="visually-hidden">
Accept terms to enable submission
</span>
</form>
<script>
const terms = document.getElementById('terms');
const submit = document.querySelector('button[type="submit"]');
terms.addEventListener('change', () => {
submit.setAttribute('aria-disabled', !terms.checked);
if (!terms.checked) {
submit.addEventListener('click', preventClick);
} else {
submit.removeEventListener('click', preventClick);
}
});
function preventClick(e) {
e.preventDefault();
}
</script>Custom Widget Examples
<!-- Custom Widget Examples -->
<!-- Disabled Tab -->
<div role="tablist">
<button role="tab" aria-selected="true">Active Tab</button>
<button role="tab" aria-selected="false">Normal Tab</button>
<button role="tab" aria-disabled="true" aria-selected="false">
Disabled Tab
</button>
</div>
<!-- Disabled Menu Item -->
<ul role="menu">
<li role="menuitem">Cut</li>
<li role="menuitem">Copy</li>
<li role="menuitem" aria-disabled="true">
Paste (clipboard empty)
</li>
</ul>
<!-- Disabled Slider -->
<div
role="slider"
aria-disabled="true"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Volume (disabled)"
tabindex="0"
>
<!-- Slider UI -->
</div>React Examples
// React Component Examples
import { useState } from 'react';
// Form with conditional submit
function SignupForm() {
const [termsAccepted, setTermsAccepted] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const isDisabled = !termsAccepted || isSubmitting;
const handleSubmit = (e) => {
e.preventDefault();
if (isDisabled) return; // Important: prevent action when disabled
setIsSubmitting(true);
// Submit logic...
};
return (
<form onSubmit={handleSubmit}>
<label>
<input
type="checkbox"
checked={termsAccepted}
onChange={(e) => setTermsAccepted(e.target.checked)}
/>
I accept the terms
</label>
<button
type="submit"
aria-disabled={isDisabled}
className={isDisabled ? 'btn-disabled' : 'btn-primary'}
>
{isSubmitting ? 'Submitting...' : 'Create Account'}
</button>
</form>
);
}
// Custom Disabled Button Component
function DisabledButton({
children,
disabled,
disabledReason,
onClick,
...props
}) {
const handleClick = (e) => {
if (disabled) {
e.preventDefault();
return;
}
onClick?.(e);
};
return (
<button
{...props}
aria-disabled={disabled}
aria-describedby={disabled && disabledReason ? 'disabled-reason' : undefined}
onClick={handleClick}
className={`btn ${disabled ? 'btn-disabled' : 'btn-primary'}`}
>
{children}
{disabled && disabledReason && (
<span id="disabled-reason" className="sr-only">
{disabledReason}
</span>
)}
</button>
);
}
// Usage
<DisabledButton
disabled={!hasPermission}
disabledReason="You need admin access to perform this action"
>
Delete User
</DisabledButton>Best Practices
Use aria-disabled on custom widgets (divs with role="button") instead of disabled attribute
Always prevent the action in JavaScript when aria-disabled="true"
Provide visual styling that clearly indicates the disabled state
Use aria-describedby to explain why an element is disabled
For native form elements, prefer the disabled attribute unless you need focusability
Test that disabled elements cannot be activated via click or keyboard
Don't forget to prevent clicks—aria-disabled alone doesn't stop interaction
Don't use aria-disabled on elements that should be truly non-interactive
Don't forget to update the value when the disabled state changes
Don't use both disabled and aria-disabled on the same element
Common Use Cases
Accessibility Notes
Screen Reader Announcements
Screen readers announce aria-disabled elements as "dimmed" or "unavailable" (varies by reader). Users can focus on the element and hear its label plus the disabled state. Example: "Submit, dimmed, button".
Keyboard Interaction
Unlike native disabled elements, aria-disabled elements remain in the tab order and can receive focus. Ensure you prevent activation via Enter/Space keys in addition to click events. This provides a better experience for keyboard users who want to explore all controls.
Explaining Why It's Disabled
A key benefit of aria-disabled is the ability to explain why something is unavailable. Use aria-describedby to link to a message explaining why the control is disabled. This is especially helpful for complex forms with prerequisites.

