Componentes · Ola 2 · Navegación
Tabs
Pestañas para cambiar entre vistas del mismo contexto sin salir de la página. La pestaña activa se marca con la barra de luz de la selección; se recorren con las flechas y, si no entran, se desplazan de costado.
import { Tabs, TabsList, TabsTrigger, TabsPanel } from '@archeblack/ui';
Ejemplos
Pestañas
Tabs con bind:value, un TabsList con nombre, un TabsTrigger por pestaña y un TabsPanel por panel, unidos por value.
Tráfico estable. 184.302 solicitudes en las últimas 24 horas.
Último despliegue hace 6 minutos desde la rama main.
Sin errores en la última hora.
Dominio, variables de entorno y permisos del equipo.
<script lang="ts">
import { Tabs, TabsList, TabsPanel, TabsTrigger } from '@archeblack/ui';
let value = $state('summary');
</script>
<div style="width: 100%">
<Tabs bind:value>
<TabsList aria-label="Secciones del proyecto">
<TabsTrigger value="summary">Resumen</TabsTrigger>
<TabsTrigger value="deploys">Despliegues</TabsTrigger>
<TabsTrigger value="logs">Registros</TabsTrigger>
<TabsTrigger value="settings">Ajustes</TabsTrigger>
</TabsList>
<TabsPanel value="summary">
<p style="margin: 0">Tráfico estable. 184.302 solicitudes en las últimas 24 horas.</p>
</TabsPanel>
<TabsPanel value="deploys">
<p style="margin: 0">Último despliegue hace 6 minutos desde la rama main.</p>
</TabsPanel>
<TabsPanel value="logs">
<p style="margin: 0">Sin errores en la última hora.</p>
</TabsPanel>
<TabsPanel value="settings">
<p style="margin: 0">Dominio, variables de entorno y permisos del equipo.</p>
</TabsPanel>
</Tabs>
</div> Activación manual
Con activationMode='manual', las flechas mueven el foco y Enter o espacio abren la pestaña.
1.204 visitas únicas.
8.911 visitas únicas.
36.502 visitas únicas.
<script lang="ts">
import { Tabs, TabsList, TabsPanel, TabsTrigger } from '@archeblack/ui';
let value = $state('day');
</script>
<!--
Activación manual: las flechas solo mueven el foco y la pestaña se abre con Enter o espacio.
Sirve cuando abrir un panel es costoso (una consulta, un gráfico pesado).
-->
<div style="width: 100%">
<Tabs bind:value activationMode="manual">
<TabsList aria-label="Período del informe">
<TabsTrigger value="day">Hoy</TabsTrigger>
<TabsTrigger value="week">Últimos 7 días</TabsTrigger>
<TabsTrigger value="month">Últimos 30 días</TabsTrigger>
</TabsList>
<TabsPanel value="day"><p style="margin: 0">1.204 visitas únicas.</p></TabsPanel>
<TabsPanel value="week"><p style="margin: 0">8.911 visitas únicas.</p></TabsPanel>
<TabsPanel value="month"><p style="margin: 0">36.502 visitas únicas.</p></TabsPanel>
</Tabs>
</div> Con conteo y deshabilitada
Una pestaña admite un Badge sm con un conteo. disabled apaga una pestaña y las flechas la saltan.
12 incidencias esperan respuesta.
148 incidencias cerradas este año.
Sin incidencias archivadas.
<script lang="ts">
import { Badge, Tabs, TabsList, TabsPanel, TabsTrigger } from '@archeblack/ui';
let value = $state('open');
</script>
<div style="width: 100%">
<Tabs bind:value>
<TabsList aria-label="Incidencias">
<TabsTrigger value="open">Abiertas <Badge size="sm">12</Badge></TabsTrigger>
<TabsTrigger value="closed">Cerradas <Badge size="sm">148</Badge></TabsTrigger>
<TabsTrigger value="archived" disabled>Archivadas</TabsTrigger>
</TabsList>
<TabsPanel value="open"><p style="margin: 0">12 incidencias esperan respuesta.</p></TabsPanel>
<TabsPanel value="closed"><p style="margin: 0">148 incidencias cerradas este año.</p></TabsPanel
>
<TabsPanel value="archived"><p style="margin: 0">Sin incidencias archivadas.</p></TabsPanel>
</Tabs>
</div> Muchas pestañas
Si no entran, la fila se desplaza de costado y el borde que esconde pestañas se desvanece. Con las flechas, la pestaña enfocada se trae a la vista entera.
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
Ajustes de «General».
<script lang="ts">
import { Tabs, TabsList, TabsPanel, TabsTrigger } from '@archeblack/ui';
const sections = [
['general', 'General'],
['domains', 'Dominios'],
['env', 'Variables de entorno'],
['team', 'Equipo'],
['billing', 'Facturación'],
['integrations', 'Integraciones'],
['security', 'Seguridad'],
['advanced', 'Avanzado']
];
let value = $state('general');
const label = $derived(sections.find(([key]) => key === value)?.[1]);
</script>
<!-- El contenedor angosto simula una pantalla chica: la fila se desplaza de costado. -->
<div style="width: 100%; max-width: 22rem">
<Tabs bind:value>
<TabsList aria-label="Ajustes del proyecto">
{#each sections as [key, name] (key)}
<TabsTrigger value={key}>{name}</TabsTrigger>
{/each}
</TabsList>
{#each sections as [key] (key)}
<TabsPanel value={key}><p style="margin: 0">Ajustes de «{label}».</p></TabsPanel>
{/each}
</Tabs>
</div> Vertical
orientation='vertical' pone la lista a un costado; se recorre con las flechas arriba y abajo. En un idioma de derecha a izquierda, la lista y su barra pasan al otro lado.
Nombre, foto y zona horaria.
Qué avisos llegan por correo y cuáles solo en la consola.
Dos sesiones abiertas: este navegador y la app del teléfono.
<script lang="ts">
import { Tabs, TabsList, TabsPanel, TabsTrigger } from '@archeblack/ui';
let value = $state('profile');
</script>
<!-- En vertical se recorre con las flechas arriba y abajo. En un móvil, mejor en horizontal. -->
<div style="width: 100%">
<Tabs bind:value orientation="vertical">
<TabsList aria-label="Cuenta">
<TabsTrigger value="profile">Perfil</TabsTrigger>
<TabsTrigger value="notifications">Notificaciones</TabsTrigger>
<TabsTrigger value="sessions">Sesiones</TabsTrigger>
</TabsList>
<TabsPanel value="profile">
<p style="margin: 0">Nombre, foto y zona horaria.</p>
</TabsPanel>
<TabsPanel value="notifications">
<p style="margin: 0">Qué avisos llegan por correo y cuáles solo en la consola.</p>
</TabsPanel>
<TabsPanel value="sessions">
<p style="margin: 0">Dos sesiones abiertas: este navegador y la app del teléfono.</p>
</TabsPanel>
</Tabs>
</div> Props
Tabs
| Prop | Descripción |
|---|---|
bind:value string | El value de la pestaña activa. Con bind:value el producto sabe cuál está abierta. |
onValueChange? (value: string) => void | Se llama al cambiar de pestaña, con su valor, después de actualizar value y solo si el cambio se aceptó (si un bind:value de función lo rechaza, no se llama). No es onchange, para no tapar el evento change que sube desde los formularios de los paneles. |
activationMode? 'automatic' | 'manual' Por defecto 'automatic' | automatic: la pestaña se abre al llegar con las flechas. manual: las flechas mueven el foco y Enter o espacio la abren. |
orientation? 'horizontal' | 'vertical' Por defecto 'horizontal' | vertical pone la lista a un costado del panel y se recorre con las flechas arriba y abajo. |
loop? boolean Por defecto true | Si las flechas vuelven a la primera pestaña después de la última. |
disabled? boolean Por defecto false | Deshabilita todas las pestañas. |
children Snippet | Un TabsList y un TabsPanel por pestaña. |
class? ClassValue | Clases del producto; se suman a arche-tabs. |
...rest HTMLAttributes<HTMLDivElement> | Cualquier otro atributo va al <div> raíz. |
TabsList
| Prop | Descripción |
|---|---|
aria-label | aria-labelledby string | Nombre de la lista: un aria-label («Secciones del proyecto») o el id del título visible que la nombra. Uno de los dos es obligatorio por tipos. |
children Snippet | Las pestañas (TabsTrigger). |
class? ClassValue | Clases del producto; se suman a arche-tabs__list. |
...rest HTMLAttributes<HTMLDivElement> | Van al <div role="tablist">. |
TabsTrigger
| Prop | Descripción |
|---|---|
value string | Identifica la pestaña. Su TabsPanel lleva el mismo. |
disabled? boolean Por defecto false | Deshabilita esta pestaña: las flechas la saltan. |
children Snippet | El texto de la pestaña; admite un Badge con un conteo. |
class? ClassValue | Clases del producto; se suman a arche-tabs__trigger. |
...rest HTMLButtonAttributes | Van al <button role="tab">. |
TabsPanel
| Prop | Descripción |
|---|---|
value string | El value de la pestaña que muestra este panel. |
tabindex? 0 | -1 Por defecto 0 | El panel es enfocable para llegar al contenido con Tab. Si empieza con un control enfocable, puede ir -1. |
children Snippet | El contenido del panel. |
class? ClassValue | Clases del producto; se suman a arche-tabs__panel. |
...rest HTMLAttributes<HTMLDivElement> | Van al <div role="tabpanel">. |
Accesibilidad
- Sigue el patrón de pestañas de ARIA con Bits UI:
role="tablist",tabytabpanel, conaria-selected,aria-controlsyaria-labelledbyunidos por id. - Con Tab se llega a la pestaña activa (las demás tienen
tabindex="-1") y el siguiente Tab pasa al panel. Dentro de la lista se usan las flechas (izquierda y derecha, o arriba y abajo en vertical), Home y End. - Por defecto, la pestaña se abre al llegar con las flechas. Si abrir un panel es lento, usa
activationMode="manual": las flechas solo mueven el foco y Enter o espacio abren. - La lista necesita un nombre:
aria-labeloaria-labelledby. TypeScript lo exige. - La pestaña activa se marca con
aria-selected, el texto entext-strongy la barra de 2 px deselected, no solo con el color. En colores forzados la barra pasa aHighlight. - Si no entran, las pestañas se desplazan de costado sin barra de scroll. El borde que esconde pestañas se desvanece: es la señal de que la fila sigue. La pestaña que recibe el foco (con las flechas o con Tab) o que queda activa se trae a la vista entera, fuera del borde desvanecido y con su anillo de foco; solo se mueve la fila, no la página.
- Una pestaña deshabilitada se anuncia como no disponible y las flechas la saltan. Si nunca se podrá usar, mejor no mostrarla.
Qué evitar
- Pestañas para pasos de un proceso en orden (datos, pago, confirmación). Un formulario por pasos con botones de «Siguiente» y «Atrás».
- Pestañas que llevan a otras páginas (cambian la URL). Una navegación con links y
aria-current="page"; las pestañas cambian vistas dentro de la misma página. - Contenido que la persona necesita comparar, repartido en dos pestañas. Mostrarlo junto, en columnas o en una tabla.
- Una sola pestaña, o más de siete. Sin pestañas si hay una sola vista; un menú o una lista lateral si hay muchas.
- Íconos solos como pestañas. Texto corto en cada pestaña; un ícono solo no dice lo mismo a todos.