Acerca de este problema HTML
El validador W3C genera este error porque los roles ARIA deben ser compatibles con el elemento al que se aplican. Un elemento <ul> tiene un rol ARIA implícito de list, y sobrescribirlo con tabpanel crea un conflicto. El rol tabpanel señala a las tecnologías de asistencia que el elemento es un panel de contenido activado por una pestaña correspondiente. Cuando este rol se coloca en un <ul>, los lectores de pantalla pierden el significado semántico de la lista (recuento de elementos, navegación de lista, etc.) mientras que también representan incorrectamente la función del elemento en la interfaz de pestañas.
Esto importa por varias razones:
-
Accesibilidad: Los usuarios de lectores de pantalla dependen de roles correctos para navegar y entender la estructura de la página. Un
<ul>marcado comotabpanelconfunde tanto su semántica de lista como su rol en la interfaz de pestañas. -
Cumplimiento de estándares: La especificación ARIA in HTML define qué roles están permitidos en qué elementos. El rol
tabpanelno está permitido en<ul>. - Comportamiento del navegador: Los navegadores pueden manejar roles conflictivos de forma inconsistente, llevando a un comportamiento impredecible entre las tecnologías de asistencia.
La solución es sencilla: envuelve el <ul> dentro de un elemento contenedor apropiado (como un <div> o <section>) y aplica el rol tabpanel a ese contenedor en su lugar.
Ejemplos
Incorrecto: rol tabpanel en un <ul>
Esto desencadena el error de validación porque tabpanel no es un rol válido para <ul>:
<div role="tablist" aria-label="Recipe categories">
<button role="tab" aria-controls="panel-1" aria-selected="true" id="tab-1">Appetizers</button>
<button role="tab" aria-controls="panel-2" aria-selected="false" id="tab-2">Desserts</button>
</div>
<ul role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<li>Bruschetta</li>
<li>Spring rolls</li>
</ul>
<ul role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
<li>Tiramisu</li>
<li>Cheesecake</li>
</ul>
Correcto: rol tabpanel en un contenedor que envuelve el <ul>
Mueve el rol tabpanel a un <div> y anida el <ul> dentro de él. Esto preserva tanto la semántica del panel de pestañas como la semántica de la lista:
<div role="tablist" aria-label="Recipe categories">
<button role="tab" aria-controls="panel-1" aria-selected="true" id="tab-1">Appetizers</button>
<button role="tab" aria-controls="panel-2" aria-selected="false" id="tab-2">Desserts</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<ul>
<li>Bruschetta</li>
<li>Spring rolls</li>
</ul>
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
<ul>
<li>Tiramisu</li>
<li>Cheesecake</li>
</ul>
</div>
Correcto: usando <section> como el panel de pestañas
Un elemento <section> también funciona bien como contenedor de panel de pestañas, especialmente cuando el contenido del panel es más complejo:
<div role="tablist" aria-label="Project info">
<button role="tab" aria-controls="tasks-panel" aria-selected="true" id="tasks-tab">Tasks</button>
<button role="tab" aria-controls="notes-panel" aria-selected="false" id="notes-tab">Notes</button>
</div>
<section role="tabpanel" id="tasks-panel" aria-labelledby="tasks-tab">
<h2>Current tasks</h2>
<ul>
<li>Review pull requests</li>
<li>Update documentation</li>
</ul>
</section>
<section role="tabpanel" id="notes-panel" aria-labelledby="notes-tab" hidden>
<h2>Meeting notes</h2>
<p>Discussed project timeline and milestones.</p>
</section>
En una interfaz con pestañas estructurada correctamente:
-
El rol
tablistva en el contenedor que contiene los botones de pestañas. -
Cada desencadenador de pestaña obtiene
role="tab"conaria-controlsapuntando alidde su panel. -
Cada panel de contenido obtiene
role="tabpanel"en un contenedor genérico como<div>o<section>, conaria-labelledbyhaciendo referencia alidde la pestaña correspondiente. -
Los elementos de lista como
<ul>y<ol>deben permanecer dentro del panel como contenido regular, manteniendo su semántica de lista nativa.
Encuentra problemas como este automáticamente
Rocket Validator escanea miles de páginas en segundos, detectando problemas de HTML en todo tu sitio web.
Más información: