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
rolethat 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:
<ahref="#"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:
<ulrole="menu">
<lirole="none">
<ahref="#"role="menuitemcheckbox"aria-checked="true">Show notifications</a>
</li>
<lirole="none">
<ahref="#"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:
<buttonrole="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:
<divclass="tab-interface">
<divrole="tablist"aria-label="Settings">
<arole="tab"href="#panel-1"aria-selected="true"aria-controls="panel-1"id="tab-1">
General
</a>
<arole="tab"href="#panel-2"aria-selected="false"aria-controls="panel-2"id="tab-2"tabindex="-1">
Advanced
</a>
</div>
<divid="panel-1"role="tabpanel"tabindex="0"aria-labelledby="tab-1">
<p>General settings content</p>
</div>
<divid="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
<ahref="/settings"aria-selected="true">Settings</a>
Fixed: Adding the appropriate role
<ahref="/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 forcheckboxandmenuitemcheckboxroles 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:
<formaction="/search">
<inputtype="text"name="q">
<button>Search</button>
</form>
Fixed by adding an explicit type:
<formaction="/search">
<inputtype="text"name="q">
<buttontype="submit">Search</button>
</form>
Button used outside a form without type
<buttononclick="openMenu()">Menu</button>
Fixed by specifying type="button":
<buttontype="button"onclick="openMenu()">Menu</button>
Toggle button missing aria-checked
A button with role="switch" but no aria-checked attribute:
<buttontype="button"role="switch">Dark Mode</button>
Fixed by adding aria-checked:
<buttontype="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:
<buttontype="button"role="checkbox"aria-checked="false">
Enable notifications
</button>
Complete toggle example with all required attributes
<buttontype="button"role="switch"aria-checked="false"id="wifi-toggle">
Wi-Fi
</button>
<script>
document.getElementById("wifi-toggle").addEventListener("click",function(){
constisChecked=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-expanded attribute cannot be used on a plain div element without also specifying a role attribute.
The aria-expanded attribute indicates whether a grouping of content that the element owns or controls is currently expanded or collapsed. However, this attribute is only valid on elements that have an appropriate implicit or explicit role. A plain div has no implicit ARIA role, so you must assign one explicitly.
The aria-expanded attribute is commonly used with interactive roles such as button, combobox, treeitem, or link. Adding the correct role tells assistive technologies what kind of element the user is interacting with, making aria-expanded meaningful in context.
HTML Examples
❌ Invalid: aria-expanded on a plain div
<divaria-expanded="false">
Menu content
</div>
✅ Valid: aria-expanded with an appropriate role
<divrole="button"aria-expanded="false">
Menu content
</div>
Alternatively, consider using a native HTML element that already carries the correct semantics, which avoids the need for a role attribute entirely:
<buttonaria-expanded="false">
Toggle Menu
</button>
Using a native <button> is generally preferred over <div role="button"> because it comes with built-in keyboard interaction and focus behavior.
The aria-expanded attribute requires the element to have an appropriate role attribute (or be an element that natively implies one). A <span> is a generic inline element with no implicit ARIA role, so you must explicitly assign a role when using ARIA state attributes like aria-expanded.
The aria-expanded attribute indicates whether a grouping element controlled by this element is currently expanded or collapsed. It is only valid on elements with specific roles such as button, link, combobox, menuitem, or other widget roles. When a <span> uses aria-expanded without a role, validators flag it because there's no semantic context for that state.
Since this element toggles a dropdown menu and has aria-label, aria-controls, and aria-expanded, the most appropriate role is button. This tells assistive technologies that the element is interactive and can be activated.
Also note that when using role="button" on a non-interactive element like <span>, you should ensure it is focusable by adding tabindex="0" and that it handles keyboard events (Enter and Space keys).
HTML Examples
❌ Invalid: aria-expanded on a span without a role
<spanclass="navbar-dropdown-icon"
aria-expanded="false"
aria-label="List options"
aria-controls="dropdown-menu-item-1-1menu-item-2-6"
data-toggle="dropdown">
</span>
✅ Valid: adding role="button" and tabindex="0"
<spanclass="navbar-dropdown-icon"
role="button"
tabindex="0"
aria-expanded="false"
aria-label="List options"
aria-controls="dropdown-menu-item-1-1menu-item-2-6"
data-toggle="dropdown">
</span>
✅ Better: use a <button> element instead
<buttonclass="navbar-dropdown-icon"
type="button"
aria-expanded="false"
aria-label="List options"
aria-controls="dropdown-menu-item-1-1menu-item-2-6"
data-toggle="dropdown">
</button>
Using a native <button> is preferred because it is focusable and keyboard-accessible by default, without needing role or tabindex.
The summary element needs an explicit role attribute when the W3C validator detects it's being used in a context where its implicit ARIA semantics are unclear or overridden.
The summary element is designed to be used as the first child of a <details> element, where it acts as a clickable disclosure toggle. When used correctly inside <details>, it has an implicit ARIA role and doesn't need additional attributes.
This validation warning typically appears when:
- The
summaryelement is used outside of a<details>element. - The
summaryelement has an explicitroleattribute that requires additional ARIA properties (e.g.,role="checkbox"requiresaria-checked, orrole="heading"requiresaria-level).
The simplest fix is to ensure summary is used correctly as a direct child of <details>, and to remove any unnecessary or conflicting role attributes.
Example with the issue
<!-- summary outside of details triggers the warning -->
<summary>Click to expand</summary>
<p>Some content here.</p>
<!-- Or summary with an incomplete role override -->
<details>
<summaryrole="heading">Section Title</summary>
<p>Some content here.</p>
</details>
How to fix it
<!-- Use summary correctly inside details -->
<details>
<summary>Click to expand</summary>
<p>Some content here.</p>
</details>
<!-- If you need a heading role, include the required aria-level -->
<details>
<summaryrole="heading"aria-level="3">Section Title</summary>
<p>Some content here.</p>
</details>
If you don't have a specific reason to override the role, simply remove the role attribute and let the summary element keep its native semantics within <details>.
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
roleand ARIA state attributes. Anaria-checkedon 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-checkedentirely 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>
<tdaria-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>
<tablerole="grid">
<tr>
<tdrole="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>
<inputtype="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>
<tdrole="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
<tablerole="grid">
<tr>
<tdrole="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.
The aria-checked attribute is not allowed on a label element when that label is associated with a form control like a checkbox or radio button.
When a label is associated with a labelable element (via the for attribute or by nesting), the label acts as an accessible name provider — it doesn't represent the control's state itself. The aria-checked attribute is meant for elements that act as a checkbox or radio button, such as elements with role="checkbox" or role="switch", not for labels that merely describe one.
Adding aria-checked to a label creates conflicting semantics. Assistive technologies already read the checked state from the associated input element, so duplicating or overriding that state on the label causes confusion.
If you need a custom toggle or checkbox, apply aria-checked to the element that has the interactive role, not to the label.
Example with the issue
<labelfor="notifications"aria-checked="true">Enable notifications</label>
<inputtype="checkbox"id="notifications"checked>
Fixed example using a native checkbox
<labelfor="notifications">Enable notifications</label>
<inputtype="checkbox"id="notifications"checked>
The native <input type="checkbox"> already communicates its checked state to assistive technologies — no aria-checked is needed anywhere.
Fixed example using a custom toggle
If you're building a custom control without a native checkbox, apply aria-checked to the element with the appropriate role:
<spanid="toggle-label">Enable notifications</span>
<spanrole="switch"tabindex="0"aria-checked="true"aria-labelledby="toggle-label"></span>
Here, aria-checked is correctly placed on the element with role="switch", which is the interactive control. The label is a separate <span> referenced via aria-labelledby, keeping roles and states cleanly separated.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries