Generador de Pestañas CSS

Siguiente

Las pestañas están en todas partes: paneles de configuración, sitios de documentación, galerías de productos. HTML nativo no tiene un elemento de pestaña dedicado, así que los desarrolladores crean los suyos. Este generador construye una barra de pestañas sencilla en HTML + CSS: un color de acento para la pestaña activa, un radio de esquinas para los botones y un estado de hover. Pega el marcado en tu proyecto y conecta el cambio de pestañas con tu propio JavaScript.

Cómo construir pestañas

  1. 1

    Elige un color de acento

    El color de fondo y de texto de la pestaña activa. Elige un color que combine con tu marca.

  2. 2

    Define el radio de esquinas

    Redondea las esquinas superiores de los botones de pestaña. Valores más altos dan un aspecto más suave.

  3. 3

    Edita las etiquetas

    El resultado incluye tres botones, "Overview", "Details" y "Settings": renómbralos para que se ajusten a tu contenido.

  4. 4

    Copia el código

    El marcado de pestañas incluye su propio bloque <style>. Pega ambos en tu página.

  5. 5

    Añade el cambio de pestañas

    El generador produce solo la parte visual. Conecta los botones a tu propio JavaScript o librería de UI para mostrar y ocultar los paneles.

Marcado accesible correcto

<div class="tabs">
  <div role="tablist" aria-label="Información del producto">
    <button role="tab" id="tab-1" aria-selected="true"  aria-controls="panel-1" tabindex="0">Resumen</button>
    <button role="tab" id="tab-2" aria-selected="false" aria-controls="panel-2" tabindex="-1">Especificaciones</button>
    <button role="tab" id="tab-3" aria-selected="false" aria-controls="panel-3" tabindex="-1">Reseñas</button>
  </div>
  <section role="tabpanel" id="panel-1" aria-labelledby="tab-1">...</section>
  <section role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>...</section>
  <section role="tabpanel" id="panel-3" aria-labelledby="tab-3" hidden>...</section>
</div>

Atributos críticos:

  • role="tablist" envuelve los botones.
  • role="tab" en cada botón, con aria-selected y aria-controls.
  • tabindex utiliza el patrón de tabindex errante: solo la pestaña activa es 0, las demás son -1. Las teclas de flecha mueven el foco entre ellas.
  • role="tabpanel" en cada panel, con aria-labelledby apuntando a su pestaña.
  • hidden en paneles inactivos (no display: none solo, el atributo es lo que usa AT).

Contrato de teclado

Tecla Acción
Tab Mover dentro / fuera de la lista de pestañas
ArrowLeft Pestaña anterior (vuelve a la última)
ArrowRight Siguiente pestaña (vuelve a la primera)
Home Primera pestaña
End Última pestaña
Enter / Space Activar la pestaña enfocada (si la activación es manual)

Activación automática (la pestaña cambia a medida que se mueve el foco) vs. manual (el foco se mueve, la pestaña se activa al presionar Enter), WAI-ARIA permite ambas. La automática es más fácil para los usuarios videntes; la manual es mejor cuando el contenido de la pestaña es pesado para renderizar.

Estilo subrayado

[role="tablist"] {
  display: flex;
  border-bottom: 1px solid #e5e7eb;
}
[role="tab"] {
  padding: 0.75rem 1rem;
  background: transparent;
  border: 0;
  color: #6b7280;
  position: relative;
  cursor: pointer;
}
[role="tab"][aria-selected="true"] {
  color: #111827;
}
[role="tab"][aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 1rem; right: 1rem; bottom: -1px;
  height: 2px;
  background: #2563eb;
}

Estilo con pastillas

[role="tab"] {
  padding: 0.5rem 0.9rem;
  border-radius: 9999px;
  border: 0;
  background: transparent;
}
[role="tab"][aria-selected="true"] {
  background: #2563eb;
  color: #fff;
}

Enfoque visible

Siempre dibuja un anillo de enfoque cuando el enfoque llega a través del teclado:

[role="tab"]:focus-visible {
  outline: 2px solid #60a5fa;
  outline-offset: 2px;
}

El JavaScript

A grandes rasgos:

const tabs = document.querySelectorAll('[role="tab"]');
tabs.forEach(tab => {
  tab.addEventListener('click', () => activate(tab));
  tab.addEventListener('keydown', e => {
    const i = [...tabs].indexOf(tab);
    if (e.key === 'ArrowRight') tabs[(i + 1) % tabs.length].focus();
    if (e.key === 'ArrowLeft')  tabs[(i - 1 + tabs.length) % tabs.length].focus();
    if (e.key === 'Home') tabs[0].focus();
    if (e.key === 'End')  tabs[tabs.length - 1].focus();
  });
});

function activate(tab) {
  tabs.forEach(t => {
    const panel = document.getElementById(t.getAttribute('aria-controls'));
    const active = t === tab;
    t.setAttribute('aria-selected', active);
    t.setAttribute('tabindex', active ? '0' : '-1');
    panel.hidden = !active;
  });
  tab.focus();
}

Treinta líneas en total, cero dependencias.

Pestañas vs. acordeones

En pantallas estrechas, las filas de pestañas se vuelven estrechas. Patrón común: pestañas en escritorio, acordeón en móvil. Usa una consulta de contenedor o consulta de medios para cambiar el tratamiento visual sin cambiar los roles ARIA.

Preguntas frecuentes

Para pestañas accesibles, sí. Sin role="tablist" y role="tab", los lectores de pantalla tratan los botones como botones regulares y los usuarios pierden la convención de navegación. La alternativa es un acordeón simple <details> / <summary>, que tiene semántica incorporada.

La automática (la pestaña se activa a medida que se mueve el foco) está bien cuando el contenido de cada pestaña es barato de renderizar. La manual (el foco se mueve, Enter activa) es mejor cuando cambiar de pestañas desencadena un trabajo pesado como obtener o renderizar un formulario grande.

Para pestañas que contienen contenido (documentación, pestañas de productos), sí, usa un hash (#specs) o parámetro de consulta para que los enlaces puedan enlazar a una pestaña específica y la pestaña activa persista entre recargas. Para pestañas de UI (paneles de configuración) la URL es opcional.

Solo con el truco de checkbox/radio, que carece de navegación con teclas de flecha y estados ARIA. Para una implementación genuinamente accesible, el pequeño fragmento de JS vale la pena. Si necesitas alternativas renderizadas en el servidor, vincula cada pestaña a una URL única y renderiza el panel correspondiente del lado del servidor.

Herramientas relacionadas

Herramienta disponible en otros idiomas