HTML Guide
Empty aria-labelledby
on the <svg>
is invalid because it must reference one or more existing IDs with non-empty, non-whitespace text.
The aria-labelledby
attribute takes a space-separated list of element IDs (IDREFS). Each ID must exist in the document and point to elements that provide an accessible name. On <svg>
, this is commonly a <title>
or other visible text element. If you have no label to reference, either remove aria-labelledby
or provide a valid referenced element. Alternatively, use the aria-label
attribute with a text string. Do not leave aria-labelledby
empty, and ensure IDs are unique and match exactly (case-sensitive). Examples: reference a <title>
with an id
, or use aria-label
directly on the <svg>
.
HTML Examples
Example showing the issue
<svg role="img" aria-labelledby="">
<use href="#icon-star"></use>
</svg>
Fixed examples
<!-- Option A: Reference a title by ID -->
<svg role="img" aria-labelledby="starTitle">
<title id="starTitle">Favorite</title>
<use href="#icon-star"></use>
</svg>
<!-- Option B: Use aria-label instead (no referenced IDs needed) -->
<svg role="img" aria-label="Favorite">
<use href="#icon-star"></use>
</svg>
<!-- Option C: Decorative icon (no name) -->
<svg aria-hidden="true" focusable="false">
<use href="#icon-star"></use>
</svg>
Learn more:
Related W3C validator issues
labelledby is not a valid attribute for the <svg> element. Perhaps you meant aria-labelledby?
The aria-labelledby attribute establishes relationships between objects and their label(s), and its value should be one or more element IDs, which refer to elements that have the text needed for labeling.
Example:
<div id="myBillingId">Billing</div>
<div>
<div id="myNameId">Name</div>
<input type="text" aria-labelledby="myBillingId myNameId"/>
</div>
<div>
<div id="myAddressId">Address</div>
<input type="text" aria-labelledby="myBillingId myAddressId"/>
</div>
Set a non-empty list of valid ID references in the aria-labelledby attribute on the <a> element, or remove the attribute and provide an accessible name another way.
The aria-labelledby attribute takes an IDREFS value: a space-separated list of one or more element IDs, each of which must be non-empty, exist in the document, and be unique. An empty value ("") violates the ARIA/HTML constraints and triggers the validator error. On an <a> element, aria-labelledby supplies the accessible name for the link by concatenating the text from the referenced elements. If you don’t have IDs to reference, use visible link text or aria-label. Avoid leaving aria-labelledby empty (common with templating when a variable is blank); either omit the attribute entirely or populate it with valid IDs. Remember that aria-labelledby overrides other naming methods, so an empty or broken reference can result in a link with no accessible name.
HTML examples
-
Invalid (what triggers the error)
<a href="/report" aria-labelledby=""></a>
-
Fixed by referencing an existing element with a valid id
<a href="/report" aria-labelledby="report-link-text"> <svg aria-hidden="true" viewBox="0 0 16 16"></svg> </a> <span id="report-link-text">View report</span>
-
Fixed with multiple IDs (space-separated)
<a href="/apples" aria-labelledby="prefix apples-text"> <svg aria-hidden="true" viewBox="0 0 16 16"></svg> </a> <span id="prefix">Learn more: </span> <span id="apples-text">Apples</span>
-
Fixed by using visible text content (no ARIA needed)
<a href="/report">View report</a>
-
Fixed by using aria-label for an icon-only link (when no separate label element exists)
<a href="/search" aria-label="Search"> <svg aria-hidden="true" viewBox="0 0 16 16"></svg> </a>
There can only be one visible <main> element in a document. If more are needed (for example for switching between them with JavaScript), only one can be visible, the others should be hidden toggling the hidden attribute.
Example of 2 main elements, where only one is visible:
<main>
<h1>Active main element</h1>
<!-- content -->
</main>
<main hidden>
<h1>Hidden main element</h1>
<!-- content -->
</main>
An a element with both an href attribute and aria-disabled="true" is invalid; either remove aria-disabled or the href attribute.
The aria-disabled attribute is used for interactive elements to indicate that the element is perceivable as disabled by assistive technologies. However, using aria-disabled="true" in combination with an href attribute on an a element is not valid, because the link remains actionable for both user agents and assistive devices. Instead, if a link should appear disabled, you should remove the href attribute, use CSS for styling, and optionally use aria-disabled="true". If you need the element to always act as a link, avoid aria-disabled and control user access through application logic.
Incorrect:
<a href="page.html" aria-disabled="true">Visit Page</a>
Correct—Option 1: Remove aria-disabled, keep link active
<a href="page.html">Visit Page</a>
Correct—Option 2: Remove href, use aria-disabled, for non-actionable item
<a aria-disabled="true" tabindex="-1" style="pointer-events: none; color: gray;">Visit Page</a>
In the second correct example, setting tabindex="-1" prevents keyboard navigation, and pointer-events: none; makes the link unclickable, while aria-disabled="true" makes the disabled state accessible.
A role="columnheader" element must be a child of or associated with a role="row" element.
In HTML, ARIA roles such as columnheader are used to improve accessibility for assistive technologies. According to the ARIA specification, a columnheader role should appear inside an element with role="row", which itself should be inside an element with role="table" or role="grid". This structure mimics how native tables are constructed with <th> elements inside <tr>s.
Correct structure:
- role="table" or role="grid" contains one or more elements with role="row".
- Each role="row" contains one or more elements with role="columnheader" (or role="cell").
Example using ARIA roles for a simple table:
<div role="table" aria-label="Sample Table">
<div role="row">
<div role="columnheader">Name</div>
<div role="columnheader">Age</div>
</div>
<div role="row">
<div role="cell">Alice</div>
<div role="cell">30</div>
</div>
</div>
Best practice:
Whenever possible, use native table elements, which have built-in roles and accessibility, reducing the chance of ARIA misuse.
Example using native table markup:
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Alice</td>
<td>30</td>
</tr>
</table>
Ensure that any element with role="columnheader" is always contained within a parent with role="row". Avoid placing role="columnheader" directly inside a container without the appropriate role="row" ancestor.
To fix this issue, ensure that an element with role="listitem" is contained within an element with role="list" or role="group". Here’s how you can structure your HTML correctly:
Incorrect Example
<div role="listitem">Item 1</div>
<div role="listitem">Item 2</div>
Correct Example
<div role="list">
<div role="listitem">Item 1</div>
<div role="listitem">Item 2</div>
</div>
Alternatively, you can use role="group" if it’s a nested list.
Correct Example with Nested List
<div role="list">
<div role="listitem">Item 1</div>
<div role="group">
<div role="listitem">Item 1.1</div>
<div role="listitem">Item 1.2</div>
</div>
<div role="listitem">Item 2</div>
</div>
This ensures that the role="listitem" elements are correctly contained.
To fix the W3C HTML Validator issue stating that an element with a role="menuitem" must be contained in, or owned by, an element with role="menubar" or role="menu", you need to ensure that your menuitem elements are properly nested within a menubar or menu element. This is important for accessibility, as it helps assistive technologies understand the structure and relationship of the elements.
The menuitem role indicates the element is an option in a set of choices contained by a menu or menubar.
Here is a step-by-step guide to fixing this issue:
1. Using role="menubar"
If your menuitem elements are part of a horizontal menu (like a navigation bar), they should be nested within an element with role="menubar".
Example:
<nav role="menubar">
<div role="menuitem">Home</div>
<div role="menuitem">About</div>
<div role="menuitem">Contact</div>
</nav>
2. Using role="menu"
If your menuitem elements are part of a submenu or a vertical menu, they should be contained within an element with role="menu".
Example:
<div role="menu">
<div role="menuitem">Item 1</div>
<div role="menuitem">Item 2</div>
<div role="menuitem">Item 3</div>
</div>
Ensuring Proper Nesting
Ensure that all your menuitem elements are either directly or indirectly (via a child-parent relationship) contained within a menubar or menu element.
Complete Example with Nested Menus:
Here is a more complex example, including nested menus for a drop-down scenario.
Example:
<nav role="menubar">
<div role="menuitem">Home</div>
<div role="menuitem">
About
<div role="menu">
<div role="menuitem">Team</div>
<div role="menuitem">History</div>
</div>
</div>
<div role="menuitem">Contact</div>
</nav>
In this example, the main navigation (menubar) contains menuitem elements, and one of those menuitem elements contains a nested menu with additional menuitem elements inside it.
By ensuring your menuitem elements are contained within appropriate parent elements (menubar or menu), you will resolve the W3C HTML Validator issue and improve your web page’s accessibility.
Elements with the role tab must either be a child of an element with the tablist role, or have their id part of the aria-owns property of a tablist.
An element with the tab role controls the visibility of an associated element with the tabpanel role. The common user experience pattern is a group of visual tabs above, or to the side of, a content area, and selecting a different tab changes the content and makes the selected tab more prominent than the other tabs.
Example:
<div class="tabs">
<div role="tablist" aria-label="Sample Tabs">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">
First Tab
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Second Tab
</button>
</div>
<div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
<p>Content for the first panel</p>
</div>
<div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
<p>Content for the second panel</p>
</div>
</div>
The aria-* attributes are part of the WAI-ARIA (Web Accessibility Initiative-Accessible Rich Internet Applications) suite. They are used to improve the accessibility of web pages. However, when we use an input element with a type attribute whose value is hidden, we imply that the element is invisible and has no interaction with the user. Therefore, it doesn’t make sense to add aria-* attributes to it.
To fix this issue, you need to remove the aria-* attributes from the input element with type=hidden. Here is an example:
<!-- Wrong code -->
<input type="hidden" name="referer" value="https://example.com" aria-invalid="false">
<!-- Correct code -->
<input type="hidden" name="referer" value="https://example.com">
The attribute xmlns:serif is not valid. Check this guide for more information on this issue.