
Este tutorial te permite crear pestañas funcionales con HTML, CSS y JavaScript. La idea es que puedas añadir los archivos CSS y JavaScript a la página y aplicar unas cuantas clases a los divs anidados para que todo funcione. También intentaremos que el marcado sea semánticamente correcto añadiendo atributos ARIA a los elementos que toca. Eso sí, no te lo tomes al pie de la letra, porque no estoy seguro de haberlo hecho del todo bien. En cualquier caso, dar sentido a tu HTML siempre merece la pena.
See the Pen
Onglets HTLM/CSS/JS by Damien Flandrin (@dam62500)
on CodePen.0
El HTML de las pestañas ( tabs )
La estructura de estas pestañas podría ser algo así. Primero un div con la clase tabs y, dentro, otros dos divs: uno con la clase tab-registers y otro con la clase tab-bodies. El primer botón que hay dentro de tab-register está enlazado con el primer elemento de tab-bodies. A uno de los botones le podemos dar la clase active-tab para que sea la pestaña activa.
Pestañas HTML
<div class="tabs">
<div class="tab-registers">
<button class="active-tab">Tab 1</button>
<button>Tab 2</button>
<button>Tab 2</button>
</div>
<div class="tab-bodies">
<div style="display:block;">
Contenu Tab 1
</div>
<div style="display:none;">
Contenu Tab 2
</div>
<div style="display:none;">
Contenu Tab 3
</div>
</div>
</div>El JavaScript de las pestañas ( tabs )
Empezamos obteniendo una colección HTML con todos los elementos que llevan la clase tabs y la recorremos en un bucle después de convertirla en lista con Array.from(list_like). El callback del bucle recibe el propio elemento y su índice. Necesitaremos ese índice para identificar cada grupo de pestañas de forma única.
Pestañas JavaScript
Array.from(document.querySelectorAll('.tabs')).forEach((tab_container, TabID) => {
...
})Después guardamos en variables los elementos que nos interesan, es decir tabs-registers y tab-bodies.
Pestañas JavaScript
const registers = tab_container.querySelector('.tab-registers');
const bodies = tab_container.querySelector('.tab-bodies');Seguimos: obtenemos el registro activo pero, como puede estar indefinido, en ese caso lo fijamos al primer botón. En cualquiera de los dos casos añadimos la clase active-tab al elemento.
Pestañas JavaScript
let activeRegister = registers.querySelector('.active-tab');
activeRegister = activeRegister ? activeRegister : registers.children[0]
activeRegister.classList.add('active-tab')A continuación llamamos a la función changeBody() que, como su nombre indica, oculta todos los cuerpos salvo el que corresponde al registro, es decir a la pestaña actual. Llamamos a esa misma función cada vez que cambia la pestaña.
Ahora recorremos también todos los elementos que están directamente dentro del contenedor de registros: los botones, es decir, las propias pestañas. En cada uno definimos el atributo aria-controls, que indica qué otro elemento controla, y definimos el id correspondiente en el cuerpo asociado. Ese id se construye con el id del grupo de pestañas y el índice del botón, así que es único.
Después añadimos un event listener al botón: quitamos la clase de pestaña activa del registro actual, sustituimos el contenido de la variable por el nuevo registro actual y le añadimos a su vez la clase de pestaña activa. Por último, llamamos a la función changeBody().
Pestañas JavaScript
Array.from(registers.children).forEach((el, i) => {
el.setAttribute('aria-controls', `${TabID}_${i}`)
bodies.children[i]?.setAttribute('id', `${TabID}_${i}`)
el.addEventListener('click', (ev) => {
let activeRegister = registers.querySelector('.active-tab');
activeRegister.classList.remove('active-tab')
activeRegister = el;
activeRegister.classList.add('active-tab')
changeBody(registers, bodies, activeRegister)
})
})Pasemos ahora a la función changeBody(). Dentro volvemos a recorrer los registros hijos y tomamos el índice de cada iteración. Si existe un cuerpo en ese índice, decidimos si su propiedad de visualización es block o none según cuál sea el registro actual. Hacemos esa comprobación porque puede haber más registros que cuerpos. Después definimos también el atributo aria-expanded del botón, que indica al usuario si el panel, o el botón que lleva a un panel, está desplegado o no.
Pestañas JavaScript
function changeBody() {
Array.from(registers.children).forEach((el, i) => {
if (bodies.children[i]) {
bodies.children[i].style.display = el == activeRegister ? 'block' : 'none'
}
el.setAttribute('aria-expanded', el == activeRegister ? 'true' : 'false')
})
}El CSS de las pestañas
Pestañas CSS
.tabs {
font-family: 'Lucida Sans', sans-serif;
font-size: 20px;
}
.tabs .tab-registers {
display: flex;
background-color: RGB(255, 255, 255);
}
.tabs button {
padding: 0.5em;
background-color: RGB(255, 255, 255);
border: none;
font: inherit;
}
.tabs .tab-registers button:hover {
cursor: pointer;
}
.tabs .tab-bodies {
padding: 0.5em;
background-color: RGB(235, 235, 235);
flex-grow: 1;
overflow-y: auto;
}
.tabs button.active-tab {
background-color: rgb(235, 235, 235);
}

