Saltar al contenido principal

Pestañas

Las pestañas (tabs) permiten alternar entre varios paneles de información dentro de una misma ventana.

Ejemplo

Panel 1

Texto de ejemplo del panel 1.

Panel 2

Texto de ejemplo del panel 2.

Panel 3

Texto de ejemplo del panel 3.

Nota: En este ejemplo la navegación con teclado se realiza usando las teclas de dirección. La flecha izquierda y derecha para cambiar de pestaña, la flecha abajo para enfocar el panel correspondiente, y la combinación mayúsculas + tabulador para devolver el foco a las pestañas.

HTML
<div class="tablist" role="tablist">  
    <a href="#panel1" role="tab">Panel 1</a>
    <a href="#panel2" role="tab">Panel 2</a>
    <a href="#panel3" role="tab">Panel 3</a>
</div>
<div class="tabcontent" role="tabpanel" id="panel1">  
    <h2>Panel 1</h2>
    ...
</div>  
<div class="tabcontent" role="tabpanel" id="panel2">  
    <h2>Panel 2</h2>
    ...
</div>  
<div class="tabcontent" role="tabpanel" id="panel3">  
    <h2>Panel 3</h2>
    ...
</div>  

En el código HTML incluimos los siguientes roles y atributos ARIA:

  • El rol tablist para indicar que se trata de un grupo de elementos de tipo pestaña.
  • El rol tab para identificar a los enlaces como pestañas que seleccionan el contenido a mostrar.
  • El rol tabpanel para identificar a los paneles de contenido asociados a las pestañas.
JavaScript
(function() {
    const tablist = document.querySelector('.tablist');
    const tabs = document.querySelectorAll('.tablist a');
    const panels = document.querySelectorAll('.tabcontent');

    // Función de selección de pestaña
    const switchTab = (oldTab, newTab) => {
        newTab.focus();
        newTab.removeAttribute('tabindex');
        newTab.setAttribute('aria-selected', 'true');
        oldTab.removeAttribute('aria-selected');
        oldTab.setAttribute('tabindex', '-1');
        let index = Array.prototype.indexOf.call(tabs, newTab);
        let oldIndex = Array.prototype.indexOf.call(tabs, oldTab);
        panels[oldIndex].hidden = true;
        panels[index].hidden = false;
    }

    // Cambia el foco para cada pestaña
    Array.prototype.forEach.call(tabs, (tab, i) => {
        tab.setAttribute('id', 'tab' + (i + 1));
        tab.setAttribute('tabindex', '-1');

    // Maneja los eventos de ratón
    tab.addEventListener('click', e => {
        e.preventDefault();
        let currentTab = tablist.querySelector('[aria-selected]');
        if (e.currentTarget !== currentTab) {
            switchTab(currentTab, e.currentTarget);
        }
    });

    // Maneja los eventos de teclado
    tab.addEventListener('keydown', e => {
        let index = Array.prototype.indexOf.call(tabs, e.currentTarget);
        let dir = e.which === 37 ? index - 1 : e.which === 39 ? index + 1 : e.which === 40 ? 'down' : null;
        if (dir !== null) {
            e.preventDefault();
            dir === 'down' ? panels[i].focus() : tabs[dir] ? switchTab(e.currentTarget, tabs[dir]) : void 0;
        }
        });
    });

    // Añade atributos a los paneles y los oculta
    Array.prototype.forEach.call(panels, (panel, i) => {
        panel.setAttribute('tabindex', '-1');
        let id = panel.getAttribute('id');
        panel.setAttribute('aria-labelledby', tabs[i].id);
        panel.hidden = true;
    });

    // Activa la primera pestaña y muestra el primer panel
    tabs[0].removeAttribute('tabindex');
    tabs[0].setAttribute('aria-selected', 'true');
    panels[0].hidden = false;
})();

El código JavaScript añade los siguientes roles y atributos ARIA:

  • El atributo aria-selected, que indica si un elemento está seleccionado o no.
  • El atributo aria-labelledby, que asocia cada panel de contenido con su pestaña correspondiente.
  • El atributo tabindex="-1" para que las pestañas inactivas no estén en la secuencia de tabulación.
  • El atributo hidden para ocultar los paneles que no están activos.

Créditos: Este código está basado en el ejemplo Tab Interface de Heydon Pickering.