Loading Developer Playground

Loading ...

Skip to main content
ARIA ATTRIBUTEWidget Attributes

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.

Value Type
true | false
Common Use
Form Controls
Compare To
disabled attribute

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

Submit buttons before form validation
Features requiring authentication
Premium features for free users
Menu items that need context
Tabs that are temporarily unavailable
Actions awaiting prerequisites
Buttons during async operations
Custom widget controls (sliders, etc.)

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.

Related Attributes

Specifications & Resources