Ir al contenido

Tabs

.tabs agrupa contenidos relacionados en paneles y muestra uno a la vez. Sigue el patrón tabs de ARIA. Necesita ds-uikit.js. Para enlazar a otras páginas usa Navegación.

  • div.tabs contiene la lista de pestañas div.tabs__list (role="tablist" y aria-label) y los paneles.
  • Cada pestaña es un button.tabs__tab con role="tab", id, aria-selected, aria-controls="<id del panel>" y data-ds-toggle="tab". Las inactivas llevan tabindex="-1".
  • Cada panel es un div.tabs__panel con role="tabpanel", aria-labelledby="<id de la pestaña>" y tabindex="0". Los inactivos llevan hidden.

El aspecto por defecto es una línea bajo la pestaña activa, como nav--underline.

<div class="tabs">
<div class="tabs__list" role="tablist" aria-label="Detalles del plan">
<button type="button" class="tabs__tab" role="tab" id="tab-resumen" aria-selected="true" aria-controls="panel-resumen" data-ds-toggle="tab">Resumen</button>
<button type="button" class="tabs__tab" role="tab" id="tab-incluye" aria-selected="false" aria-controls="panel-incluye" tabindex="-1" data-ds-toggle="tab">Qué incluye</button>
<button type="button" class="tabs__tab" role="tab" id="tab-plazos" aria-selected="false" aria-controls="panel-plazos" tabindex="-1" data-ds-toggle="tab">Plazos</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-resumen" aria-labelledby="tab-resumen" tabindex="0">
<p>Un sitio web a la medida de tu negocio, listo para crecer contigo.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-incluye" aria-labelledby="tab-incluye" tabindex="0" hidden>
<p>Diseño, desarrollo, hosting y soporte durante tres meses.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-plazos" aria-labelledby="tab-plazos" tabindex="0" hidden>
<p>Entre tres y seis semanas, según la cantidad de páginas.</p>
</div>
</div>

tabs--pills rellena la pestaña activa con primary, como nav--pills.

<div class="tabs tabs--pills">
<div class="tabs__list" role="tablist" aria-label="Facturación">
<button type="button" class="tabs__tab" role="tab" id="tab-mensual" aria-selected="true" aria-controls="panel-mensual" data-ds-toggle="tab">Mensual</button>
<button type="button" class="tabs__tab" role="tab" id="tab-anual" aria-selected="false" aria-controls="panel-anual" tabindex="-1" data-ds-toggle="tab">Anual</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-mensual" aria-labelledby="tab-mensual" tabindex="0">
<p>Pagas mes a mes y puedes cancelar cuando quieras.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-anual" aria-labelledby="tab-anual" tabindex="0" hidden>
<p>Pagas una vez al año y te regalamos dos meses.</p>
</div>
</div>

tabs--vertical pone las pestañas en columna, a la izquierda del panel. Agrega aria-orientation="vertical" a la lista: así los lectores de pantalla anuncian que se recorre con arriba y abajo. Se puede combinar con tabs--pills.

<div class="tabs tabs--vertical">
<div class="tabs__list" role="tablist" aria-label="Configuración" aria-orientation="vertical">
<button type="button" class="tabs__tab" role="tab" id="tab-perfil" aria-selected="true" aria-controls="panel-perfil" data-ds-toggle="tab">Perfil</button>
<button type="button" class="tabs__tab" role="tab" id="tab-cuenta" aria-selected="false" aria-controls="panel-cuenta" tabindex="-1" data-ds-toggle="tab">Cuenta</button>
<button type="button" class="tabs__tab" role="tab" id="tab-avisos" aria-selected="false" aria-controls="panel-avisos" tabindex="-1" data-ds-toggle="tab">Notificaciones</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-perfil" aria-labelledby="tab-perfil" tabindex="0">
<p>Tu nombre, tu foto y cómo te ven los demás.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-cuenta" aria-labelledby="tab-cuenta" tabindex="0" hidden>
<p>Correo, contraseña y métodos de pago.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-avisos" aria-labelledby="tab-avisos" tabindex="0" hidden>
<p>Elige qué avisos recibes por correo.</p>
</div>
</div>

Con disabled, la pestaña no se puede activar y el teclado la salta.

<div class="tabs">
<div class="tabs__list" role="tablist" aria-label="Pedido">
<button type="button" class="tabs__tab" role="tab" id="tab-productos" aria-selected="true" aria-controls="panel-productos" data-ds-toggle="tab">Productos</button>
<button type="button" class="tabs__tab" role="tab" id="tab-envio" aria-selected="false" aria-controls="panel-envio" tabindex="-1" data-ds-toggle="tab">Envío</button>
<button type="button" class="tabs__tab" role="tab" id="tab-pago" aria-selected="false" aria-controls="panel-pago" tabindex="-1" data-ds-toggle="tab" disabled>Pago</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-productos" aria-labelledby="tab-productos" tabindex="0">
<p>Tienes tres productos en el carro.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-envio" aria-labelledby="tab-envio" tabindex="0" hidden>
<p>Elige la dirección y el tipo de envío.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-pago" aria-labelledby="tab-pago" tabindex="0" hidden>
<p>Paga con tarjeta o transferencia.</p>
</div>
</div>

Los íconos van dentro de la pestaña con aria-hidden="true". Si la pestaña solo tiene ícono, ponle aria-label.

<div class="tabs">
<div class="tabs__list" role="tablist" aria-label="Contacto">
<button type="button" class="tabs__tab" role="tab" id="tab-correo" aria-selected="true" aria-controls="panel-correo" data-ds-toggle="tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m3 7 9 6 9-6" /></svg>
Correo
</button>
<button type="button" class="tabs__tab" role="tab" id="tab-telefono" aria-selected="false" aria-controls="panel-telefono" tabindex="-1" data-ds-toggle="tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2" /></svg>
Teléfono
</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-correo" aria-labelledby="tab-correo" tabindex="0">
<p>Escríbenos y te respondemos en menos de un día hábil.</p>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-telefono" aria-labelledby="tab-telefono" tabindex="0" hidden>
<p>Llámanos de lunes a viernes, de 9:00 a 18:00.</p>
</div>
</div>
  • Clic: una pestaña con data-ds-toggle="tab" muestra su panel (el de aria-controls). Si ya está activa, no pasa nada.
  • Teclado: las flechas izquierda y derecha (arriba y abajo en vertical) pasan a la pestaña anterior o siguiente y la activan; en los extremos dan la vuelta. Inicio y Fin van a la primera y a la última. Saltan las deshabilitadas.
  • Actualiza aria-selected, tabindex (solo la activa queda en el orden de Tab) y hidden de los paneles.
  • Transición: el panel anterior se desvanece (is-closing) y después aparece el nuevo (is-opening). Los paneles se ocultan con hidden, sin quitarlos del DOM.
const plan = dsUIKit.tabs('#plan'); // .tabs o selector
plan.show(2); // índice (desde 0)
plan.show(document.querySelector('#tab-plazos')); // o la pestaña

En React, los atributos funcionan igual. Para cambiar de pestaña desde código: tabs(ref.current).show(1) (con import { tabs } from './js/ds-uikit.esm.js').

Evento Cuándo
ds:open En el panel nuevo, antes de mostrarse. Con preventDefault() se cancela el cambio.
ds:opened En el panel nuevo, al terminar de mostrarse.
ds:close En el panel anterior, antes de ocultarse. No se puede cancelar.
ds:closed En el panel anterior, al terminar de ocultarse.

event.detail.trigger es la pestaña que se activó, o null si fue por la API. Más detalles en JavaScript.

// Carga el contenido del panel la primera vez que se muestra
document.addEventListener('ds:open', (e) => {
if (e.detail.component === 'tabs' && e.target.id === 'panel-plazos') cargarPlazos();
});
  • La lista lleva role="tablist" y un aria-label que describe el grupo. Cada pestaña apunta a su panel con aria-controls y cada panel se nombra con su pestaña (aria-labelledby).
  • Teclado: Tab entra a la pestaña activa y sale al panel; las flechas recorren las pestañas (foco itinerante: solo la activa tiene tabindex="0"). La pestaña se activa al recibir el foco.
  • El panel lleva tabindex="0" para que se pueda llegar a él con Tab aunque no tenga elementos enfocables. Si su contenido empieza con un enlace o un botón, puedes quitarlo.
  • En vertical, aria-orientation="vertical" en la lista.
  • Usa disabled en el <button> para deshabilitar una pestaña (también sirve aria-disabled="true").
  • Los paneles inactivos están ocultos con hidden: no se leen ni se enfocan.
  • Con «reducir movimiento» activado, cambia de panel sin transición.
Clase Uso
tabs Contenedor de las pestañas y los paneles.
tabs__list Lista de pestañas (role="tablist").
tabs__tab Pestaña (role="tab"). La activa lleva aria-selected="true".
tabs__panel Panel (role="tabpanel"). Los inactivos llevan hidden.
tabs--pills Píldoras: la pestaña activa se rellena con primary.
tabs--vertical Pestañas en columna, a la izquierda del panel.
is-opening, is-closing Estados del fundido (los pone el JS).
VariableValor por defectoUso
--ds-tabs-gapvar(--ds-space-4)Separación entre las pestañas y el panel.
--ds-tabs-list-gapvar(--ds-space-6)Separación entre pestañas.
--ds-tabs-list-border-width1pxGrosor de la línea bajo las pestañas.
--ds-tabs-list-border-colorvar(--ds-color-border)Color de la línea bajo las pestañas.
--ds-tabs-tab-padding-yvar(--ds-space-2)Espacio vertical interno de la pestaña.
--ds-tabs-tab-padding-x0Espacio horizontal interno de la pestaña.
--ds-tabs-tab-gapvar(--ds-space-2)Separación entre ícono y texto.
--ds-tabs-tab-font-sizevar(--ds-font-size-base)
--ds-tabs-tab-font-weightvar(--ds-font-weight-medium)
--ds-tabs-tab-colorvar(--ds-color-text-muted)Color de la pestaña.
--ds-tabs-tab-bgtransparentFondo de la pestaña.
--ds-tabs-tab-radius0Radio de las esquinas de la pestaña.
--ds-tabs-tab-hover-colorvar(--ds-color-text)Color en hover.
--ds-tabs-tab-hover-bgvar(--ds-tabs-tab-bg)Fondo en hover.
--ds-tabs-tab-active-colorvar(--ds-color-primary)Color de la pestaña activa.
--ds-tabs-tab-active-bgvar(--ds-tabs-tab-bg)Fondo de la pestaña activa.
--ds-tabs-icon-size1.25emTamaño de los íconos.
--ds-tabs-indicator-size3pxGrosor de la línea de la pestaña activa.
--ds-tabs-indicator-colorcurrentColorColor de la línea de la pestaña activa.
--ds-tabs-focus-colorvar(--ds-color-primary)Color del contorno de foco.
--ds-tabs-disabled-opacity0.5Opacidad de una pestaña deshabilitada.
--ds-tabs-transition-durationcalc(var(--ds-duration-fast) * 0.75)Duración de cada fundido al cambiar de panel (sale el anterior y entra el nuevo).