Product Craft Bible
Tabs
Inicio Componentes UI Tabs
Componentes UI

Tabs

8 reglas NN/g "Tabs, Used Right" · NN/g "Tabs vs. Accordions"W3C WAI-ARIA APG Tabs Pattern · a11y-collective "Accessible tabs" · James Bateson "Making tab patterns accessible"W3C WAI-ARIA APG Tabs Pattern (automatic vs. manual activation)Material Design 3 Tabs guidelines (scrollable vs. fixed) · NN/g "Tabs, Used Right"
53

Tabs

8 reglas
483

Usa tabs solo para contenido paralelo y mutuamente excluyente, nunca para pasos secuenciales

Los tabs sirven para vistas paralelas del mismo objeto donde el usuario elige una a la vez y no necesita comparar las demas: "Resumen", "Detalles", "Reviews" de un producto. No sirven para pasos secuenciales de un wizard (Datos, Pago, Confirmación), donde el orden importa y el tab control deja saltar o retroceder rompiendo el flujo. Tampoco para mezclar navegación entre páginas con tabs in-page: NN/g advierte que combinar ambos contextos en un mismo control desorienta. Si los labels son largos, el contenido es breve, o el contexto es móvil, un accordion suele ser mejor opción que los tabs.

NN/g "Tabs, Used Right" · NN/g "Tabs vs. Accordions"
Preferir
Resumen
Detalles técnicos
Reviews
Vistas paralelas del mismo producto. El usuario salta a cualquiera sin orden obligatorio y ninguna depende de la otra.
Evitar
1Datos
2Dirección
3Pago
4Confirmar
Un wizard secuencial montado sobre tabs. El usuario puede saltar a "Pago" sin completar "Datos" y romper el flujo.
Pasos con orden → usa un stepper, no tabs
484

Implementa el patrón ARIA completo: tablist / tab / tabpanel con aria-selected y aria-controls

El patrón oficial WAI-ARIA APG exige tres roles: role="tablist" en el contenedor, role="tab" en cada pestana y role="tabpanel" en cada panel. El tab activo lleva aria-selected="true" y los inactivos aria-selected="false"; cada tab apunta a su panel con aria-controls y cada panel a su tab con aria-labelledby. El tablist necesita un nombre propio vía aria-label o aria-labelledby para que el lector de pantalla lo anuncie al entrar. Un <div onclick> sin roles se lee como texto plano: el usuario de lector de pantalla no sabe que es un tab, cuantos hay ni cual esta seleccionado.

W3C WAI-ARIA APG Tabs Pattern · a11y-collective "Accessible tabs" · James Bateson "Making tab patterns accessible"
Preferir
Roles ARIA conectados
<div role="tablist" aria-label="Cuenta">
  <button role="tab"
    aria-selected="true"
    aria-controls="p-perfil" id="t-perfil">Perfil</button>
</div>
<div role="tabpanel"
  id="p-perfil" aria-labelledby="t-perfil">…</div>
Evitar
div con onclick, sin roles
<div class="tab active"
  onclick="show(0)">Perfil</div>
<div class="tab" onclick="show(1)">Seguridad</div>

<div class="panel">…</div>
<!-- lector: "Perfil Seguridad", texto plano -->
485

Navega con flechas y activa al foco solo si el panel no tiene latencia

El teclado sigue un patrón preciso: Tab entra al tablist y aterriza en el tab activo, las flechas ← → (o ↑ ↓ en vertical) navegan entre tabs, y Tab de nuevo sale hacia el panel; los tabs inactivos llevan tabindex="-1" (roving tabindex). El APG recomienda la activación automática al recibir foco cuando los paneles se muestran sin latencia perceptible, lo que normalmente exige precargar su contenido. Reserva la activación manual (Enter o Space) para paneles que disparan peticiones de red: si activas en cada movimiento de flecha, cada paso lanza un request y produce flashes y estados inconsistentes.

W3C WAI-ARIA APG Tabs Pattern (automatic vs. manual activation)
Preferir
Auto · panel precargado
Vista
Datos
Notas
mueve y activa
Sin latencia: la flecha activa el tab al instante. El usuario no presiona Enter.
Manual · carga de red
Vista
Datos
Notas
mueve focoactiva
El foco se mueve sin disparar fetch; Enter carga el panel cuando el usuario decide.
Evitar
Auto + red en cada flecha
Vista
Datos
Notas
Cada → dispara un GET de 300ms+. El usuario navega rápido y desata 3 requests en cascada con flashes y estados a medias.
486

Ante overflow usa tabs scrollable o un menú "Más", nunca comprimas ni trunces

Cuando los tabs no caben en el ancho disponible hay dos estrategias validas: scrollable tabs (contenedor con overflow-x:auto y sombra o flechas que indican que hay más) o un menú "Más ▾" que agrupa los que no caben. Material 3 recomienda tabs scrollable cuando el número es alto o variable, y reserva los fixed tabs (ancho igual, todos visibles) para conjuntos pequeños y estables. Nunca comprimas los labels hasta hacerlos ilegibles ni los trunces con ellipsis sin tooltip: convertir los tabs en un carrusel ciego reduce la descubribilidad y eleva el costo de interacción.

Material Design 3 Tabs guidelines (scrollable vs. fixed) · NN/g "Tabs, Used Right"
Preferir
Scrollable · 280px
Resumen
Actividad
Archivos
Permisos
Historial
La sombra lateral revela que hay más; el gesto horizontal los alcanza
Evitar
Comprimido · 280px
Resu…
Acti…
Arch…
Perm…
Hist…
Labels truncados a 4 caracteres: nadie sabe que hay en cada tab
487

Usa tabs verticales cuando los labels son largos o las secciones son muchas

Los tabs verticales en columna izquierda resuelven dos problemas que los horizontales no pueden: labels descriptivos que no caben en una fila estrecha y listas largas de secciones que desbordarian cualquier renglon. Son la elección correcta en páginas de ajustes, dashboards y formularios multi-sección con jerarquía profunda; como criterio, más alla de un punado de secciones (LogRocket ubica el rango comodo en torno a 5-7) los horizontales empiezan a truncar. En orientación vertical se usa aria-orientation="vertical" para que las flechas ↑ ↓ sean las que naveguen entre tabs en lugar de ← →.

LogRocket "Tabs UX best practices" (criterio) · W3C WAI-ARIA APG (aria-orientation)
Preferir
Perfil
Seguridad
Notificaciones
Facturación
Integraciones
Perfil

Labels completos y legibles, indicador izquierdo de 3px en la sección activa, y el rail no se desplaza al cambiar de panel. Las flechas ↑ ↓ navegan con aria-orientation="vertical".

Evitar
Horizontal · 5+ secciones largas
Perfil
Segu…
Noti…
Fact…
Inte…
Una fila estrecha no aguanta labels descriptivos: todo se trunca
488

Badge de conteo: oculta el número al lector pero incluyelo en el aria-label del tab

Un badge de conteo sobre un tab necesita doble tratamiento de accesibilidad: el elemento visual lleva aria-hidden="true" para que el lector de pantalla no lea el número como texto suelto, y ese conteo se incorpora al aria-label del tab completo ("Mensajes, 5 sin leer"). Cuando el conteo cambia en vivo, anuncialo desde una region aria-live="polite" sin mover el foco. Nunca comuniques el significado solo con color: un punto rojo sin número ni texto alternativo es invisible para lectores de pantalla y para personas con daltonismo, en contra de WCAG 1.4.1 Use of Color.

GitHub MUI #22070 (badge aria-hidden + aria-label) · Setproduct "Badge UI design" (aria-live) · WCAG 2.2 SC 1.4.1
Preferir
Mensajes
Archivados
Spam
aria-label="Mensajes, 5 sin leer"
badge aria-hidden="true" · cambios vía aria-live="polite"
Evitar
Mensajes
Archivados
Spam
Punto rojo sin número ni texto: invisible para lector y para daltonismo
489

El tab activo pide dos señales visuales; el foco de teclado, 3:1 de contraste y 2px

El tab seleccionado nunca debe distinguirse solo por color: usa al menos dos indicadores simultaneos (subrayado + negrita, color + borde inferior, fondo + peso tipografico). En tabs el foco de teclado y la selección son estados distintos, así que el indicador de foco es critico y debe cumplir WCAG 2.4.11 (AA): contraste mínimo 3:1 entre el estado con foco y sin foco, y un área equivalente al perimetro de un trazo de 2px CSS alrededor del componente. Un outline:2px solid con offset cumple el mínimo; si es punteado o discontinuo hay que duplicar el grosor para compensar los huecos. Jamas outline:none sin reemplazo visible.

NN/g "Tabs, Used Right" (dos señales) · W3C WCAG 2.2 SC 2.4.11 Focus Appearance · Sara Soueidan "Focus indicators"
Preferir
Activo: texto oscuro + peso 600 + borde inferior 2px (dos señales)
Foco de teclado: outline 2px solid, offset 2px, contraste 3:1 (WCAG 2.4.11)
Evitar
Resumen
Detalles
Reviews
Activo solo por color (gris → azul) y outline:none. Sin señal redundante ni foco visible.
490

En móvil limita los tabs visibles, soporta swipe entre paneles y respeta el target tactil mínimo

En pantallas pequeñas muestra pocos tabs a la vez (como criterio, 3-5); si hay más, activa scroll horizontal con indicador de que hay contenido lateral, y nunca recurras a tabs verticales: la superficie es insuficiente. El gesto de swipe horizontal debe mover el panel (no los tabs) y mantenerse sincronizado con la tab activa. El área tactil de cada tab debe respetar el mínimo normativo de WCAG: 24×24px CSS por SC 2.5.8 Target Size (Minimum, AA), idealmente 44×44px por SC 2.5.5 (AAA); para labels chicos se expande el área de toque invisible, no se reduce el texto. El "48px" de los blogs de UI es una recomendación comoda, no la norma a citar.

W3C WCAG 2.2 SC 2.5.8 Target Size (Minimum) · SC 2.5.5 Target Size (Enhanced) · Material Design 3 Tabs (scroll horizontal) · LogRocket (criterio 3-5)
Preferir
Hoy
Semana
Mes
Año

8.420pasos hoy. El track del panel se desliza con el dedo y la tab activa se sincroniza sola.

52.140pasos esta semana. El swipe mueve el panel, no los tabs; estos siguen al panel.

Swipe sobre el panel cambia la tab activa · target ≥ 24×24px (WCAG 2.5.8)
Evitar
Hoy
Sem…
Mes
Año
Q1
Q2
Hist
7 tabs de 24px alto y texto de 9px en 375px: ni se leen ni se tocan