HTML Guides for aria-checked
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 <a> element has an implicit ARIA role of link (when it has an href) or generic (when it doesn’t). Certain ARIA state attributes, like aria-checked, are only valid on elements with specific roles that support them. For instance, aria-checked is designed for roles like checkbox, menuitemcheckbox, radio, switch, or option. If you place aria-checked on an <a> element without assigning one of these compatible roles, the validator raises this error because the attribute doesn’t make sense in the context of the element’s current role.
This matters for several reasons. Screen readers and other assistive technologies rely on the relationship between roles and their supported states to convey meaningful information to users. An aria-checked attribute on a plain link creates a confusing experience — the user hears that something is “checked” but the element is announced as a link, which isn’t a concept that supports checked/unchecked states. This mismatch can make interfaces unusable for people relying on assistive technology.
To fix this issue, you need to either:
- Add an appropriate role that supports the ARIA state attribute you’re using.
- Use a more semantically appropriate element, such as <input type="checkbox"> or <button>, which natively supports the concept of being checked or toggled.
- Remove the unsupported ARIA attribute if it doesn’t actually reflect the element’s behavior.
Examples
Incorrect: aria-checked without a compatible role
This triggers the validation error because <a> doesn’t support aria-checked without an explicit role:
<a href="#" aria-checked="true">Dark mode</a>
Fixed: Adding a compatible role
Adding role="menuitemcheckbox" (within a menu context) or role="switch" makes aria-checked valid:
<ul role="menu">
<li role="none">
<a href="#" role="menuitemcheckbox" aria-checked="true">Show notifications</a>
</li>
<li role="none">
<a href="#" role="menuitemcheckbox" aria-checked="false">Dark mode</a>
</li>
</ul>
Fixed: Using a <button> with role="switch" instead
In many cases, a <button> is a better semantic fit than an <a> for toggle-like interactions:
<button role="switch" aria-checked="true">Dark mode</button>
Correct: Tab list using <a> elements with proper roles
When building a tab interface with anchor elements, each tab needs role="tab" along with supporting attributes like aria-selected:
<div class="tab-interface">
<div role="tablist" aria-label="Settings">
<a role="tab" href="#panel-1" aria-selected="true" aria-controls="panel-1" id="tab-1">
General
</a>
<a role="tab" href="#panel-2" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Advanced
</a>
</div>
<div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
<p>General settings content</p>
</div>
<div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
<p>Advanced settings content</p>
</div>
</div>
Incorrect: aria-selected on a plain <a> without a role
<a href="/settings" aria-selected="true">Settings</a>
Fixed: Adding the appropriate role
<a href="/settings" role="tab" aria-selected="true">Settings</a>
When choosing a fix, always consider whether the <a> element is truly the best choice. If the element doesn’t navigate the user to a new URL, a <button> is usually more appropriate. Reserve <a> for actual navigation, and use ARIA roles and states only when they accurately describe the element’s behavior in the interface.
The HTML specification defines <button> as a versatile interactive element, but its behavior changes depending on context. When a <button> is placed inside a <form> without a type attribute, it defaults to type="submit", which can cause unexpected form submissions. The validator flags this because relying on the implicit default is ambiguous and error-prone. Explicitly setting the type attribute makes the button’s intent clear to both developers and browsers.
The three valid values for the type attribute are:
- submit — submits the parent form’s data to the server.
- reset — resets all form controls to their initial values.
- button — performs no default action; behavior is defined via JavaScript.
When a <button> is given an ARIA role of checkbox, switch, or menuitemcheckbox, the validator expects an aria-checked attribute to accompany it. These roles describe toggle controls that have a checked or unchecked state, so assistive technologies need to know the current state. Without aria-checked, screen readers cannot communicate whether the control is on or off, making the interface inaccessible.
The aria-checked attribute accepts the following values:
- true — the control is checked or on.
- false — the control is unchecked or off.
- mixed — the control is in an indeterminate state (valid for checkbox and menuitemcheckbox roles only).
How to fix it
For standard buttons, add the type attribute with the appropriate value. If the button triggers JavaScript behavior and is not meant to submit a form, use type="button". If it submits a form, use type="submit" explicitly to make the intent clear.
For toggle buttons, ensure the <button> has both a role attribute (such as checkbox or switch) and an aria-checked attribute that reflects the current state. You should also include type="button" to prevent unintended form submission. Use JavaScript to toggle the aria-checked value when the user interacts with the button.
Examples
Missing type attribute
This triggers the validator warning because the type is not specified:
<form action="/search">
<input type="text" name="q">
<button>Search</button>
</form>
Fixed by adding an explicit type:
<form action="/search">
<input type="text" name="q">
<button type="submit">Search</button>
</form>
Button used outside a form without type
<button onclick="openMenu()">Menu</button>
Fixed by specifying type="button":
<button type="button" onclick="openMenu()">Menu</button>
Toggle button missing aria-checked
A button with role="switch" but no aria-checked attribute:
<button type="button" role="switch">Dark Mode</button>
Fixed by adding aria-checked:
<button type="button" role="switch" aria-checked="false">Dark Mode</button>
Checkbox-style toggle button
A button acting as a checkbox must include both role="checkbox" and aria-checked:
<button type="button" role="checkbox" aria-checked="false">
Enable notifications
</button>
Complete toggle example with all required attributes
<button type="button" role="switch" aria-checked="false" id="wifi-toggle">
Wi-Fi
</button>
<script>
document.getElementById("wifi-toggle").addEventListener("click", function () {
const isChecked = this.getAttribute("aria-checked") === "true";
this.setAttribute("aria-checked", String(!isChecked));
});
</script>
In this example, the type="button" prevents form submission, the role="switch" tells assistive technologies this is a toggle, and aria-checked is updated dynamically to reflect the current state. This ensures the button is fully accessible and passes validation.
The aria-checked attribute communicates the checked state of an interactive widget to assistive technologies. According to the WAI-ARIA specification, this attribute is only permitted on elements that have a role supporting the “checked” state — such as checkbox, switch, radio, menuitemcheckbox, or menuitemradio. A plain <td> element has an implicit role of cell (or gridcell when inside a role="grid" table), neither of which supports aria-checked. When the validator encounters aria-checked on a <td> without a compatible role, it flags the element as invalid.
This matters for several reasons:
- Accessibility: Screen readers and other assistive technologies rely on the relationship between role and ARIA state attributes. An aria-checked on an element without a recognized checkable role creates a confusing or broken experience — users may not understand that the cell is supposed to be interactive.
- Standards compliance: The ARIA in HTML specification defines strict rules about which attributes are allowed on which roles. Violating these rules means your HTML is technically invalid.
- Browser behavior: Browsers may ignore aria-checked entirely when it’s used on an element without a valid role, making the attribute useless.
How to fix it
You have two main approaches depending on what your <td> is meant to do:
1. Add an appropriate role attribute. If the table cell genuinely represents a checkable control (for example, in an interactive data grid), add role="checkbox", role="switch", or another appropriate checkable role to the <td>, along with tabindex for keyboard accessibility.
2. Remove aria-checked and use a real control. If the cell simply contains a checkbox or toggle, place an actual <input type="checkbox"> inside the <td> and remove the ARIA attributes from the cell itself. Native HTML controls already communicate their state to assistive technologies without extra ARIA.
Examples
❌ Incorrect: aria-checked without a role
<table>
<tr>
<td aria-checked="true">Selected</td>
<td>Item A</td>
</tr>
</table>
This triggers the error because <td> has the implicit role of cell, which does not support aria-checked.
✅ Fix: Add a compatible role to the <td>
<table role="grid">
<tr>
<td role="checkbox" aria-checked="true" tabindex="0">Selected</td>
<td>Item A</td>
</tr>
</table>
Here the <td> explicitly has role="checkbox", which supports aria-checked. The tabindex="0" makes it keyboard-focusable, and role="grid" on the table signals that cells may be interactive.
✅ Fix: Use a native checkbox inside the <td>
<table>
<tr>
<td>
<label>
<input type="checkbox" checked>
Selected
</label>
</td>
<td>Item A</td>
</tr>
</table>
This approach is often the best option. The native <input type="checkbox"> already conveys its checked state to assistive technologies, and no ARIA attributes are needed on the <td>.
❌ Incorrect: Mismatched role and aria-checked
<table>
<tr>
<td role="button" aria-checked="false">Toggle</td>
<td>Item B</td>
</tr>
</table>
The button role does not support aria-checked. This would trigger a different but related validation error.
✅ Fix: Use a role that supports aria-checked
<table role="grid">
<tr>
<td role="switch" aria-checked="false" tabindex="0">Toggle</td>
<td>Item B</td>
</tr>
</table>
The switch role supports aria-checked and is appropriate for toggle-style controls.
Ready to validate your sites?
Start your free trial today.