Saltar al contenido principal

tdn-tabs

Paquete: @tiendana/ngx-core/ui

Tira horizontal de pestañas operable con teclado, construida sobre los ítems .nav del sistema de diseño. Sirve para cualquier fila de opciones excluyentes que cambian lo que muestra una pantalla: secciones de un formulario, el alcance de una búsqueda, un filtro, los modos de un editor. Para el avance por pasos use tdn-stepper; para navegar entre rutas use enlaces.

Disponible desde @tiendana/ngx-core 0.8.0. El slot trailing, iconPosition y la forma del host llegaron en 0.8.1.

Características​

✅ Controlado: no guarda la selección; dibuja activeId, emite selected y el consumidor lo escribe de vuelta
✅ Semántica a elección: radio (por defecto), tab o none
✅ Teclado completo: una sola parada con Tab y flechas, Inicio y Fin, la selección sigue al foco
✅ Desbordamiento: scroll horizontal con puntos de ajuste y flechas que aparecen sobre los extremos
✅ Variantes: compact (sin píldora) y floating (glassmorphism)
✅ Slot trailing para dibujar un marcador propio después de la etiqueta

Requiere web-foundation

Todos los colores salen de los estilos .nav de @tiendana/web-foundation, que responden a .scheme-dark. Sin esa hoja de estilos los ítems se ven como botones sin estilo.

Selector​

tdn-tabs

API​

Inputs​

InputTipoDefaultDescripción
itemsTdnTab[]requeridoLas pestañas, en el orden en que se dibujan
activeIdstring''id de la pestaña actual. Un id que no coincide con ningún ítem deja la tira sin selección y sin ítems alcanzables con Tab
semantics'tab' | 'radio' | 'none''radio'Qué es la tira para la tecnología asistiva
ariaLabelstring''Nombre accesible del grupo, ya traducido. Vacío no escribe aria-label
compactbooleanfalseQuita la píldora de fondo. Booleano simple: se enlaza [compact]="true"
floatingbooleanfalseAplica el glassmorphism flotante (.nav--is-floating) a la pista. Booleano simple
iconPosition'before' | 'after''after'Lado de la etiqueta en el que va el icono del ítem
trailingTemplateRef<{ $implicit: TdnTab }> | nullnullReemplaza lo que se dibuja después de la etiqueta; recibe el ítem como contexto
compact y floating no son atributos booleanos

Son entradas booleanas simples, sin booleanAttribute: escribir <tdn-tabs compact> no las activa. Enlácelas: [compact]="true".

Outputs​

OutputTipoDescripción
selectedOutputEmitterRef<string>Emite el id de la pestaña elegida, por clic o por flecha. Se emite incluso si ya era la activa

Interfaz TdnTab​

CampoTipoDescripción
idstringIdentificador estable, único en la tira. Lo emite selected y se compara con activeId
labelstringTexto visible, ya traducido: la librería nunca traduce
icon?stringLigadura de Material. Se ignora si hay svgIcon
svgIcon?stringSímbolo registrado en el MatIconRegistry de la app. Tiene prioridad sobre icon
title?stringTooltip nativo, para etiquetas abreviadas o iconos que cargan el significado
dot?booleanDibuja el punto de estado del sistema de diseño tras la etiqueta; --dot-color es transparente en reposo, --color-forrest al pasar el cursor y --color-natura cuando el ítem está activo. No se dibuja si hay trailing
onError?booleanAplica el tratamiento de error (.nav__item--on-error) al icono del ítem
panelId?stringid del panel que controla; se escribe como aria-controls. Solo tiene sentido con semantics="tab"
data?unknownLo que necesite su plantilla trailing; la librería nunca lo lee
Tipos TdnTab y TdnTabsSemantics
export interface TdnTab {
id: string;
label: string;
icon?: string;
svgIcon?: string;
title?: string;
dot?: boolean;
onError?: boolean;
panelId?: string;
data?: unknown;
}

export type TdnTabsSemantics = 'tab' | 'radio' | 'none';

Miembros públicos​

canScrollLeft y canScrollRight (signals que el componente actualiza al medir y que muestran las flechas; no los escriba desde fuera), containerRole e itemRole (computed), y los métodos select(id), onKey(event), onScroll() y scrollBy(-1 | 1). select(id) emite selected como lo hace un clic y no cambia activeId por sí mismo; el resto son manejadores de la plantilla que no están pensados para llamarse desde fuera.

Contenido proyectado​

No proyecta contenido. El único punto de extensión es el input trailing, una ng-template cuyo contexto implícito (let-item) es el TdnTab, con su data incluido.

<tdn-tabs [items]="sections()" [activeId]="section()" (selected)="section.set($event)" [trailing]="state" />

<ng-template #state let-item>
@if (item.data?.pending) {
<tdn-busy-loader style="--busy-loader-size: 16px" />
}
</ng-template>

Con trailing presente se reemplazan el icono (cuando iconPosition es 'after') y el punto; un icono con iconPosition="before" se sigue dibujando.

Semántica y accesibilidad​

semanticsContenedorÍtemÚselo cuando
'radio' (defecto)radiogroupradio con aria-checkedHay una sola zona de resultados que la tira filtra o acota
'tab'tablisttab con aria-selected y aria-controls (desde panelId)Cada ítem revela su propio panel
'none'sin rolbotón sin rol ni estadoEnlaces dentro de la página o scroll-spy
  • Nombre el grupo con ariaLabel en 'radio' y 'tab'. Déjelo vacío con 'none': ARIA no permite nombre en un elemento sin rol.
  • Teclado: una sola parada de Tab (tabindex itinerante: solo el ítem activo tiene 0). Flecha derecha o abajo y flecha izquierda o arriba pasan al siguiente o anterior y dan la vuelta; Inicio y Fin van al primero y al último. La selección sigue al foco, de modo que cada flecha emite selected.
  • Las flechas de desbordamiento son aria-hidden, quedan fuera del orden de Tab y no roban el foco al pulsarse, así que un campo de búsqueda junto a la tira conserva el cursor.
  • El ítem enfocado dibuja un contorno de 2px con --color-forrest.
  • Con semantics="tab" los ítems no llevan id: dé a cada role="tabpanel" su propio aria-label.
Trampas que fallan sin error
  • Un activeId que no coincide con ningún ítem deja todos los ítems con tabindex="-1": no se llega con Tab y las flechas no hacen nada. Empiece siempre con un id válido.
  • No escribir selected de vuelta en activeId deja la tira pegada a la pestaña anterior.
  • Los degradados de desbordamiento se pintan desde --bg-1dp; sobre otra superficie se ven como una banda.

Desbordamiento​

Cuando los ítems no caben, la pista hace scroll horizontal con puntos de ajuste y aparecen chevrones sobre los extremos; cada pulsación avanza cerca del 60% del ancho visible. Las flechas se miden al hacer scroll, al cambiar items y al redimensionarse la tira. Cuando cambia activeId, la pestaña activa se desliza al centro.

Estilos​

  • Clases del host: tdn-tabs--compact cuando compact está activo. El host toma el radio de la pista (--border-radius-xl, 0 en compact), de modo que una sombra o contorno que el consumidor ponga sobre tdn-tabs sigue la píldora.
  • Clases internas de web-foundation: .nav, .nav__item, .nav__item--active, .nav__item--on-error, .nav--is-floating; locales: .nav--compact, .nav-arrow, .nav-arrow--left, .nav-arrow--right, .nav-arrow--hidden.
  • compact usa peso normal y semibold solo en el ítem activo.
  • El componente no declara propiedades CSS propias; el color y el relleno vienen de los tokens del sistema de diseño (--bg-1dp, --color-forrest, --color-text-primary, --spacing-*, --font-*).

Ejemplos y Demos​

Uso básico​

Cargando demo...
Ver código
Cargando demo...
Ver código

Desbordamiento​

Cargando demo...
Ver código

Alcance de una búsqueda​

<tdn-tabs
[items]="scopes()"
[activeId]="scope()"
semantics="radio"
[ariaLabel]="'search_scope' | translate"
(selected)="scope.set($event)" />