Acerca de este problema HTML
La especificación WAI-ARIA define un modelo de propiedad estricto para los roles relacionados con pestañas. Un elemento con role="tab" controla la visibilidad de un elemento asociado role="tabpanel", y se espera que las pestañas estén agrupadas dentro de un tablist. Esta relación es cómo las tecnologías de asistencia como los lectores de pantalla entienden y comunican el patrón de interfaz de pestañas a los usuarios — por ejemplo, anunciando “pestaña 2 de 4” cuando el foco se mueve entre pestañas.
Cuando una tab no está contenida en o es propiedad de un tablist, los lectores de pantalla no pueden determinar cuántas pestañas existen en el grupo, qué pestaña está actualmente seleccionada, o cómo navegar entre ellas. Esto rompe fundamentalmente la accesibilidad de la interfaz de pestañas, haciéndola confusa o inutilizable para personas que dependen de tecnologías de asistencia.
Hay dos maneras de establecer la relación requerida:
-
Contención directa: Coloca los elementos
role="tab"como hijos directos del elementorole="tablist". Este es el enfoque más común y directo. -
Usando
aria-owns: Si la estructura DOM impide el anidamiento directo, añadearia-ownsal elementotablistcon una lista separada por espacios de valoresidque referencien cada pestaña. Esto le dice a las tecnologías de asistencia que eltablistes propietario de esas pestañas aunque no sean hijos directos en el DOM.
Ejemplos
Incorrecto: pestaña fuera de un tablist
En este ejemplo, los botones role="tab" son hermanos del tablist en lugar de hijos de él, lo que desencadena el error de validación.
<div class="tabs">
<div role="tablist" aria-label="Sample Tabs"></div>
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
First Tab
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2">
Second Tab
</button>
</div>
Correcto: pestañas como hijos directos de tablist
La solución más simple es colocar los elementos role="tab" directamente dentro del elemento role="tablist".
<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>
Correcto: usando aria-owns cuando el anidamiento DOM no es posible
Si tu diseño o framework hace difícil anidar las pestañas directamente dentro del tablist, puedes usar aria-owns para establecer la relación programáticamente.
<div class="tabs">
<div role="tablist" aria-label="Sample Tabs" aria-owns="tab-1 tab-2"></div>
<div class="tab-wrapper">
<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>
Notas adicionales
-
Cada elemento
role="tab"debe usararia-selectedpara indicar qué pestaña está activa ("true") y cuáles no ("false"). -
Usa
aria-controlsen cada pestaña para referenciar elidde sutabpanelasociado. -
Usa
aria-labelledbyen cadatabpanelpara apuntar de vuelta a su pestaña controladora. -
Establece
tabindex="0"en la pestaña activa ytabindex="-1"en las pestañas inactivas para soportar la navegación por teclado con las teclas de flecha dentro deltablist. -
Incluye siempre un
aria-labeloaria-labelledbyen eltablistpara darle un nombre accesible.
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: