HTML Guides for disabled
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The core problem is that aria-disabled="true" is purely an accessibility hint — it communicates a disabled state to assistive technologies like screen readers, but it has no effect on the actual behavior of the element. When an a element has an href attribute, the browser treats it as a valid hyperlink regardless of any ARIA attributes. Users can still click it, follow it via keyboard navigation, and navigate to its destination. This mismatch between the announced state (“disabled”) and actual behavior (“fully functional link”) creates a confusing and misleading experience, particularly for users of assistive technologies.
The W3C validator flags this combination because it violates the principle that ARIA states should accurately reflect an element’s true interactive state. A link that claims to be disabled but still works undermines user trust and can cause real usability problems.
Why this matters
- Accessibility: Screen readers will announce the link as disabled, but users who activate it will be unexpectedly navigated away. This is disorienting and violates WCAG guidance on predictable behavior.
- Standards compliance: The HTML specification and ARIA in HTML requirements discourage or disallow this combination because it produces an unreliable user experience.
- Browser behavior: No browser will disable a link just because aria-disabled="true" is present. The href attribute always makes the a element an active hyperlink.
How to fix it
You have two main approaches depending on your intent:
-
The link should be active: Remove aria-disabled="true" and keep the href. If the link works, don’t mark it as disabled.
-
The link should be disabled: Remove the href attribute. Without href, the a element becomes a placeholder link that is not interactive. You can then use aria-disabled="true" to communicate the disabled state, tabindex="-1" to remove it from the keyboard tab order, and CSS to style it as visually disabled. You should also add JavaScript to prevent activation if needed.
Examples
Incorrect
This triggers the validation error because aria-disabled="true" conflicts with the presence of href:
<a href="/dashboard" aria-disabled="true">Go to Dashboard</a>
Correct — Keep the link active
If the link should function normally, simply remove the aria-disabled attribute:
<a href="/dashboard">Go to Dashboard</a>
Correct — Disable the link
If the link should be non-actionable (e.g., a navigation item the user doesn’t currently have access to), remove the href attribute and use ARIA and CSS to communicate the disabled state:
<a aria-disabled="true" tabindex="-1" role="link" class="link-disabled">Go to Dashboard</a>
.link-disabled {
color: #6c757d;
cursor: not-allowed;
pointer-events: none;
text-decoration: none;
}
In this approach:
- Removing href ensures the link is not actionable by the browser.
- aria-disabled="true" tells assistive technologies the element is disabled.
- tabindex="-1" removes the element from the keyboard tab order so users can’t Tab to it.
- role="link" preserves the link semantics so screen readers still identify it as a link (an a without href loses its implicit link role).
- The CSS provides a visual indication that the element is disabled, with pointer-events: none preventing mouse clicks and cursor: not-allowed giving a visual cue on hover.
Correct — Use a button instead
If the “link” triggers an action rather than navigating somewhere, consider using a button element instead. Buttons natively support the disabled attribute:
<button type="button" disabled>Perform Action</button>
This is the simplest and most robust solution when the element doesn’t need to be a link. The disabled attribute is natively understood by browsers and assistive technologies without any ARIA workarounds.
In HTML, boolean attributes work differently than you might expect from programming languages. They don’t accept "true" or "false" as values. Instead, the presence of the attribute means it’s active, and its absence means it’s inactive. This is defined in the WHATWG HTML Living Standard, which states that a boolean attribute’s value must either be the empty string or a case-insensitive match for the attribute’s name.
This means there are exactly three valid ways to write the disabled attribute:
- disabled (no value)
- disabled="" (empty string)
- disabled="disabled" (attribute name as value)
Any other value — including "true", "false", "yes", "no", or "1" — is invalid and will trigger a W3C validation error.
A common and dangerous misunderstanding is that disabled="false" will make an element not disabled. It won’t. Because boolean attributes are activated by their presence alone, disabled="false" still disables the element. The browser sees the disabled attribute is present and treats the element as disabled, completely ignoring the "false" value. This can lead to confusing bugs where elements appear permanently disabled.
This issue affects all elements that support the disabled attribute, including <input>, <button>, <select>, <textarea>, <fieldset>, <optgroup>, and <option>. The same rules apply to other boolean attributes like checked, readonly, required, autofocus, and hidden.
Why this matters
- Standards compliance: Using invalid attribute values violates the HTML specification and produces W3C validation errors.
- Maintainability: Developers reading disabled="true" or disabled="false" may misunderstand the intent, especially if they assume "false" removes the disabled state.
- Framework pitfalls: Some JavaScript frameworks dynamically set disabled="true" or disabled="false" as string values. When the rendered HTML reaches the browser, both values result in a disabled element, which is rarely the intended behavior.
How to fix it
- To disable an element, add the disabled attribute with no value, or use disabled="" or disabled="disabled".
- To enable an element, remove the disabled attribute entirely. Don’t set it to "false".
- In JavaScript, use the DOM property element.disabled = true or element.disabled = false, or use element.removeAttribute('disabled') to enable it. Avoid element.setAttribute('disabled', 'false').
Examples
❌ Invalid: using "true" and "false" as values
<form>
<input type="text" disabled="true">
<select disabled="false">
<option>Option A</option>
</select>
<button type="submit" disabled="true">Submit</button>
</form>
Both the "true" and "false" values are invalid. Additionally, disabled="false" still disables the <select> element, which is almost certainly not what was intended.
✅ Valid: correct boolean attribute usage
<form>
<input type="text" disabled>
<select>
<option>Option A</option>
</select>
<button type="submit" disabled="disabled">Submit</button>
</form>
Here, the <input> and <button> are disabled using valid syntax. The <select> is enabled because the disabled attribute has been removed entirely.
✅ Valid: toggling disabled state with JavaScript
<form>
<input type="text" id="username" disabled>
<button type="button" id="toggle">Enable field</button>
<script>
document.getElementById('toggle').addEventListener('click', function () {
var field = document.getElementById('username');
field.disabled = !field.disabled;
});
</script>
</form>
Using the disabled DOM property (a real boolean) is the correct way to toggle the disabled state dynamically. This avoids the pitfall of setting string values like "true" or "false" on the attribute.
Boolean attributes in HTML work differently from regular attributes. Their mere presence on an element makes them “true,” and their absence makes them “false.” According to the WHATWG HTML specification, a boolean attribute may only have three valid representations:
- The attribute name alone (e.g., disabled)
- The attribute with an empty string value (e.g., disabled="")
- The attribute with its own name as the value (e.g., disabled="disabled")
Any other value — including seemingly intuitive ones like "true", "yes", or "no" — is invalid and will cause the W3C HTML Validator to report an error such as: Bad value “disabled” for attribute “disabled” on element “input” (or a similar message referencing whatever invalid value you used).
Why this matters
Standards compliance: Using invalid values violates the HTML specification, which can lead to unpredictable behavior as browsers evolve.
Misleading behavior: A common pitfall is writing disabled="false" and expecting the input to be enabled. This does not work as expected — because the attribute is still present, the element remains disabled regardless of the value. This can lead to confusing bugs where developers think they’re enabling a field but it stays disabled.
Accessibility: Assistive technologies rely on the DOM’s interpretation of boolean attributes. While browsers typically handle invalid values gracefully by treating any present disabled attribute as true, sticking to valid values ensures the most consistent behavior across screen readers and other tools.
Templating and frameworks: This issue frequently arises when templating engines or JavaScript frameworks insert string values into boolean attributes. If your template outputs disabled="true" or disabled="false", you should instead conditionally include or omit the attribute entirely.
How to fix it
- Remove the value entirely — just write the attribute name by itself.
- Use an empty string — write disabled="" if your tooling requires an explicit value.
- Use the canonical form — write disabled="disabled" if you need XHTML compatibility.
- To enable an element, remove the disabled attribute completely rather than setting it to "false".
Examples
Incorrect usage
These all trigger a validation error because the values are not valid for a boolean attribute:
<input type="text" disabled="yes">
<input type="text" disabled="true">
<input type="text" disabled="false">
<input type="text" disabled="1">
<button disabled="no">Submit</button>
Note that disabled="false" and disabled="no" still disable the element — the browser sees the attribute is present and treats it as true.
Correct usage
All three of these are valid ways to disable an input:
<input type="text" disabled>
<input type="text" disabled="">
<input type="text" disabled="disabled">
To have an enabled input, simply omit the attribute:
<input type="text">
Handling dynamic values in JavaScript
If you need to toggle the disabled state dynamically, use the DOM property rather than setting an attribute value:
<form>
<input type="text" id="username">
<button type="button" id="toggle">Toggle</button>
<script>
document.getElementById("toggle").addEventListener("click", function () {
var input = document.getElementById("username");
input.disabled = !input.disabled;
});
</script>
</form>
Setting element.disabled = true or element.disabled = false in JavaScript correctly adds or removes the attribute from the DOM without producing invalid markup.
Other boolean attributes
This same rule applies to all boolean attributes in HTML, including checked, readonly, required, hidden, autoplay, loop, muted, and others. For example:
<!-- Incorrect -->
<input type="checkbox" checked="true">
<input type="email" required="required_field">
<!-- Correct -->
<input type="checkbox" checked>
<input type="email" required>
When in doubt, use the simplest form: just the attribute name with no value. It’s the most readable, the most concise, and fully compliant with the HTML specification.
Ready to validate your sites?
Start your free trial today.