HTML Guide
Use a valid landmark or list role: remove role="list"
from the section
, or replace the element with a proper list (ul
/ol
) or a container that supports role="list"
.
The role
attribute must use values allowed by ARIA for the given context. A section
element is a landmark and must not be given role="list"
. If you intend to mark up a list of items, use semantic list elements: ul
/ol
with li
. If you truly need ARIA list semantics (e.g., for custom components), use a neutral container (div
) with role="list"
and child elements with role="listitem"
. Prefer native HTML lists over ARIA roles because they provide built-in semantics and better accessibility. Examples:
-
Native list: use
ul
+li
. -
ARIA list (only if native markup isn’t possible):
div role="list"
containingdiv role="listitem"
.
HTML Examples
Example showing the validation error
<section role="list">
<div>Item A</div>
<div>Item B</div>
</section>
Fixed using native list semantics (recommended)
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
Fixed using ARIA roles on neutral elements (when custom UI prevents native lists)
<div role="list">
<div role="listitem">Item A</div>
<div role="listitem">Item B</div>
</div>
Learn more:
Related W3C validator issues
Using role="article" on a <section> element is invalid because article is not a permitted value for the role attribute.
The role attribute in HTML is used to define ARIA roles that describe the purpose of an element for assistive technologies. Only specific, predefined ARIA roles are valid per the WAI-ARIA specification. article is not a recognized ARIA role—use document or other appropriate roles instead, or omit the role attribute entirely. The <article> and <section> elements already have implicit roles, so manual role assignment is rarely necessary or useful for these elements.
Valid uses:
- Use <article> without a role attribute for content that is self-contained and intended to be independently distributable or reusable.
- Use <section> for grouping related content and omit the role attribute unless a specific ARIA landmark role is needed (such as region).
Example: use <article> for standalone content
<article>
<h2>News headline</h2>
<p>News content goes here.</p>
</article>
Example: use <section> without a role attribute for generic grouping
<section>
<h2>Introduction</h2>
<p>Section content.</p>
</section>
Using role="section" on a <section> element is unnecessary and not recommended.
The <section> element is a semantic HTML5 element that is used to define sections within a document. A <section> inherently carries the semantics of a structural region, so you don’t need to explicitly declare a role attribute for it. The role attribute in HTML is mainly used to enhance accessibility by explicitly defining the purpose of an element when the element’s native HTML semantics are missing or insufficient. However, in this case, since <section> is already semantically meaningful, assigning a role="section" results in redundancy and can cause validation warnings or errors.
HTML5 and ARIA (Accessible Rich Internet Applications) guidelines suggest only using roles when absolutely necessary. Misusing roles can lead to confusion for assistive technologies, potentially impacting user accessibility.
Here’s a correct use of the <section> element without the role attribute:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document Title</title>
</head>
<body>
<header>
<h1>Website Header</h1>
</header>
<section>
<h2>Section Heading</h2>
<p>This is a paragraph within the section.</p>
</section>
<footer>
<p>Website Footer</p>
</footer>
</body>
</html>
By removing role="section", you leverage the semantic meaning that the <section> element already provides, ensuring cleaner, more accessible, and standards-compliant HTML.
Remove the role="list" attribute from the ul element.
The ul (unordered list) element is inherently recognized as a list in HTML. As such, it is automatically associated with the semantic role of a list. Adding role="list" to a ul is redundant and can also confuse browsers and screen readers, potentially leading to inconsistent behavior or impaired accessibility. This attribute is unnecessary because the list role is implicitly defined for this element through HTML specifications, and W3C HTML validation flags it to ensure semantic clarity and best practices.
Example of Incorrect role Usage:
<ul role="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
Corrected Example Without Unnecessary role:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
By excluding the role="list", the code adheres to semantic clarity and best practices, complying with W3C standards while maintaining accessibility.
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>
The HTML <figure> element is used to encapsulate media content, such as an image or graphic, along with a descriptive <figcaption>. When a <figcaption> is present within a <figure>, it inherently provides the semantics of the <figure>, making it self-explanatory without needing an additional role attribute.
Explanation
-
<figure> element: Represents self-contained content, potentially with an optional caption specified by a <figcaption> element. This is inherently recognized for its semantics as a figure with a caption.
-
<figcaption> element: Provides a caption or description for the content of the <figure>. This helps in describing the media or content included in the <figure> element.
-
role attribute: This attribute is used to define an explicit accessibility role for an element. However, in cases where the element’s native semantics are explicit and sufficient, such as a <figure> with a <figcaption>, adding a role attribute might override or conflict with the inherent meaning.
Solution
Remove the role attribute from the <figure> element when it contains a <figcaption>.
Example of Incorrect Code:
<figure role="figure">
<img src="cat.jpg" alt="A cute cat">
<figcaption>A cute cat looking at the camera.</figcaption>
</figure>
Corrected Code:
<figure>
<img src="cat.jpg" alt="A cute cat">
<figcaption>A cute cat looking at the camera.</figcaption>
</figure>
In the corrected example, the <figure> element does not have a role attribute, allowing it to maintain its inherent semantic value.
A role="cell" element must be a child of an element with role="row" for correct ARIA relationships.
According to the ARIA specification, role="cell" should be directly contained within a parent with role="row", which itself should usually be inside an element with role="rowgroup" or role="table". This structure allows assistive technologies to interpret your table semantics correctly.
Correct Structure Example:
<div role="table">
<div role="row">
<div role="cell">Row 1, Cell 1</div>
<div role="cell">Row 1, Cell 2</div>
</div>
<div role="row">
<div role="cell">Row 2, Cell 1</div>
<div role="cell">Row 2, Cell 2</div>
</div>
</div>
Incorrect Structure Example (missing row):
<div role="table">
<div role="cell">Cell without row</div>
</div>
How to fix:
Wrap any element with role="cell" inside an element with role="row". This ensures both validity and proper accessibility support.
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>