Tabs, Pills y Accordion para Angular | ng-hub-ui-panels
Componente de paneles de contenido para Angular que se renderiza como tabs, pills o accordion, con routing, formularios reactivos, navegación por teclado y variables CSS.
Referencia API
Aquí tienes el contrato completo de panels: todo lo que puedes enlazar, escuchar, proyectar y personalizar, reunido en un solo sitio. Enlaza lo que necesites y dale el estilo que quieras — es standalone y reactivo con signals.
Inputs
Ajusta panels a tu gusto con 40 inputs. Se enlazan como cualquier @Input de Angular.
| Nombre | Tipo | Por defecto | Descripción |
|---|---|---|---|
type | 'tabs' | 'pills' | 'accordion' | 'card' | 'tabs' | Visualización del contenedor: tabs subrayadas, pills redondeadas, paneles de accordion apilados o cards siempre visibles y sin marco. |
vertical | boolean | false | Apila la tira de cabeceras verticalmente junto al contenido (vistas tabs / pills). |
justified | boolean | false | Estira las cabeceras para repartir equitativamente el ancho disponible. |
scrollable | boolean | false | Añade botones de desplazamiento hacia atrás/adelante cuando la tira de cabeceras desborda. |
isKeysAllowed | boolean | true | Habilita la navegación con teclado (flechas / Home / End / Delete). |
multiple | boolean | false | Permite que varios paneles estén activos a la vez. En la vista de accordion todos se expanden; en las vistas de tabs/pills cada cabecera activa inicia un bloque de panel visible y las cabeceras inactivas siguientes permanecen agrupadas encima de ese bloque hasta que la siguiente cabecera activa inicia uno nuevo. El valor del formulario pasa a ser un array. |
flush | boolean | false | Vista de accordion: paneles de borde a borde sin bordes exteriores ni radio. |
togglePosition | 'start' | 'end' | 'end' | En <hub-panels> (vista accordion): en qué lado de la fila de cabecera se sitúa el chevron de despliegue. "end" (por defecto) lo deja detrás del encabezado; "start" lo pone delante. Solo cambia el orden visual — el DOM no se toca — y los desplazamientos son lógicos, así que "start" es el borde izquierdo en LTR y el derecho en RTL. Fija el valor por defecto de toda la app con HubPanelsConfig.togglePosition. |
variant | HubPanelVariant | string | undefined | hub-panels: acento semántico de la tira de navegación — lo siguen el tab activo y su hover, la pill activa y la cabecera de accordion activa. Los valores integrados ('primary' | 'success' | 'danger' | 'warning' | 'info') usan los tintes del design system, pero se acepta cualquier string: la tira lee --hub-sys-color-<variant> de tu aplicación. Por defecto, primary. |
bindValue | string | undefined | Ruta en notación de puntos aplicada al valor de cada panel para obtener el valor de formulario emitido (p. ej. 'meta.key'). |
compareWith | (a: unknown, b: unknown) => boolean | (a, b) => a === b | Igualdad utilizada para comparar los valores de formulario con los valores de los paneles. |
heading | string | undefined | hub-panel: cabecera de texto plano. Se ignora cuando se proporciona una plantilla hubPanelHeading. |
appearance | 'card' | 'alert' | 'card' | hub-panel: apariencia visual de un panel independiente — 'card' (por defecto) o un aviso semántico 'alert'. Se ignora en las vistas de tabs/pills/accordion. |
variant | HubPanelVariant | string | undefined | hub-panel: acento semántico del panel — colorea un alert y tiñe una card entera (reflejado como data-variant). Los valores integrados ('primary' | 'success' | 'danger' | 'warning' | 'info') usan los tintes del design system, pero se acepta cualquier string: el panel lee --hub-sys-color-<variant> de tu aplicación. Omítelo para un panel neutro. |
fill | boolean | false | Solo panel card: llena la altura del padre y deja que el cuerpo haga scroll, de modo que una región interna flex:1/min-height:0 (p. ej. una tira de pestañas + panel con scroll) quede acotada. El padre debe ser una columna flex. |
standalone | boolean (static attribute) | false | Solo panel card, atributo estático: excluye un <hub-panel> suelto de un grupo tabs/pills/accordion ancestro en la misma plantilla, de modo que se renderice como una card normal en lugar de ser capturado como una pestaña oculta. |
id | string | 'hub-panel-<n>' | hub-panel: id usado para el emparejamiento ARIA entre un tab y su panel (o entre una cabecera de accordion y su región). Se genera automáticamente como hub-panel-<n>; asígnalo cuando necesites ids estables, para un enlace profundo o un aria-controls propio. |
value | unknown | id | hub-panel: valor aportado cuando el contenedor se usa como control de formulario. |
active | boolean (model) | false | hub-panel: estado active/expanded con binding bidireccional. |
disabled | boolean | false | hub-panel: impide que el panel pueda activarse. |
removable | boolean | false | hub-panel: muestra un control ✕ y habilita la eliminación con la tecla Delete. |
removeLabel | string | 'Remove panel' | hub-panel: nombre accesible (aria-label) que se anuncia para el botón ✕ de eliminación; sobrescríbelo para localizar el control. |
routerLink | string | string[] | undefined | hub-panel: convierte el panel en un panel enrutado respaldado por un <router-outlet>. |
queryParams | Params | undefined | hub-panel: parámetros de consulta añadidos al navegar a routerLink. |
pathMatch | 'route' | 'full' | 'route' | hub-panel: comparación de URL utilizada para marcar como activo un panel enrutado. |
customClass | string | undefined | hub-panel: clases CSS adicionales aplicadas tanto al elemento del nav como al panel. |
items | HubTabNavItem[] | [] | Las pestañas seleccionables de un <hub-tab-nav>, en orden de renderizado. Cada elemento es un descriptor ligero { value, label, disabled?, id? } — la tira no posee contenido, así que value es lo que emite cuando se elige la pestaña. |
active | unknown (model) | undefined | Valor seleccionado con enlace bidireccional de un <hub-tab-nav>. Establécelo para preseleccionar una pestaña y léelo de vuelta a través de activeChange; el elemento coincidente es aquel cuyo value es igual a este. |
appearance | 'tabs' | 'pills' | 'tabs' | Aspecto visual de la tira <hub-tab-nav>: 'tabs' clásicas con subrayado (por defecto) o 'pills' redondeadas. |
justified | boolean | false | Cuando es true, las pestañas del <hub-tab-nav> se estiran para repartir el ancho disponible por igual. |
vertical | boolean | false | Cuando es true, la tira <hub-tab-nav> apila sus pestañas en vertical en lugar de disponerlas en una fila. |
mode | HubSidePanelMode | 'side' | <hub-side-panel>: 'side' acopla el panel y estrecha el contenido para hacerle sitio; 'over' lo hace flotar sobre el borde del contenido sin backdrop, bloqueo de scroll ni trampa de foco. |
position | HubSidePanelPosition | 'end' | <hub-side-panel>: borde lógico del contenedor en el que se sitúa el panel — 'end' es el borde derecho en LTR y el izquierdo con dir="rtl". |
open | boolean (model) | false | <hub-side-panel>: estado de apertura bidireccional. Cerrar oculta el panel sin destruir su contenido proyectado, así que un chat o un formulario dentro conserva su estado. |
closeOnEscape | boolean | true | <hub-side-panel>: si pulsar Escape dentro del panel lo cierra. El Escape pulsado en la página nunca se captura, y un control que ya consumió la tecla mantiene el panel abierto. |
breakpoint | number | 768 | <hub-side-panel>: ancho del contenedor en px por debajo del cual un panel side se renderiza como over, porque un panel acoplado en una pantalla estrecha aplastaría el contenido. 0 lo mantiene acoplado a cualquier ancho. |
autoFocus | boolean | false | <hub-side-panel>: si al abrir se mueve el foco dentro del panel — al primer elemento [autofocus], si no al primero tabulable, si no al propio panel. Desactivado por defecto. |
role | HubSidePanelRole | 'complementary' | <hub-side-panel>: rol de landmark — 'complementary' junto al contenido principal de la página, 'region' cuando el panel está dentro de él. |
ariaLabel | string | undefined | <hub-side-panel>: nombre accesible del landmark. Indica este o ariaLabelledBy. |
ariaLabelledBy | string | undefined | <hub-side-panel>: id del elemento que da nombre al landmark, normalmente el título de la cabecera. |
Outputs
Reacciona a lo que hace panels: 7 eventos a los que enganchar tu lógica.
| Nombre | Tipo | Descripción |
|---|---|---|
panelChange | OutputEmitterRef<PanelChangeEvent> | hub-panels: se emite cuando el usuario activa (abre) un panel diferente. Proporciona { current, prev }. |
selectPanel | OutputEmitterRef<HubPanelComponent> | hub-panel: se emite cuando el panel pasa a estar activo. |
deselectPanel | OutputEmitterRef<HubPanelComponent> | hub-panel: se emite cuando el panel deja de estar activo. |
removed | OutputEmitterRef<HubPanelComponent> | hub-panel: se emite cuando el panel se elimina mediante el botón ✕ o la tecla Delete. |
activeChange | OutputEmitterRef<boolean> | hub-panel: mitad de cambio del model bidireccional active, emitida con el nuevo estado activo/expandido del panel. |
activeChange | OutputEmitterRef<unknown> | Emitido por <hub-tab-nav> cada vez que cambia el valor seleccionado (la mitad de cambio del modelo bidireccional active), transportando el value del elemento recién seleccionado. |
openChange | OutputEmitterRef<boolean> | <hub-side-panel>: mitad de cambio del modelo bidireccional open; se emite con el nuevo estado lo cambie quien lo cambie (binding, Escape, toggle() o close()). |
Métodos
Controla panels desde el código — 6 métodos en su superficie programática.
| Nombre | Firma | Devuelve | Descripción |
|---|---|---|---|
HubPanelsComponent.selectPanel | selectPanel(panel: HubPanelComponent): void | — | Activa un panel como lo haría un clic: lo marca activo, navega si el panel está enrutado y emite panelChange. Con paneles deshabilitados no hace nada. |
HubPanelsComponent.togglePanel | togglePanel(panel: HubPanelComponent): void | — | Alterna un panel en la vista accordion, respetando multiple: sin multiple, abrir uno colapsa el resto. |
HubPanelsComponent.removePanel | removePanel(panel: HubPanelComponent, options?: { reselect?: boolean; emit?: boolean }): void | — | Elimina un panel del grupo. reselect decide si otro panel ocupa su lugar; emit, si la eliminación se notifica por panelChange. |
HubPanelsComponent.removePanelAndRefocus | removePanelAndRefocus(panel: HubPanelComponent): void | — | Elimina un panel y pasa el foco de teclado a la cabecera más cercana que quede, de modo que un borrado nunca deja el foco en el body. Es lo que llaman el botón ✕ y la tecla Delete. |
HubSidePanelComponent.toggle | toggle(force?: boolean): void | — | Abre o cierra el panel; pasa true o false para forzar un estado en lugar de alternarlo. |
HubSidePanelComponent.close | close(): void | — | Cierra el panel. Si el foco estaba dentro, vuelve al elemento que lo tenía cuando se abrió el panel. |
Templates
Hazlo tuyo — 3 plantillas para proyectar tu propio marcado.
| Nombre | Descripción | Ejemplo |
|---|---|---|
hubPanelHeading | Marca un <ng-template> dentro de un hub-panel como la cabecera personalizada de ese panel (enlace de la tira en tabs/pills, botón de despliegue en accordion), reemplazando el input de cabecera de texto plano. | <hub-panel>
<ng-template hubPanelHeading>
<i class="fa-solid fa-gear"></i> Settings <hub-badge color="primary" shape="rounded">3</hub-badge>
</ng-template>
Panel content
</hub-panel> |
hubPanelHeader / hubPanelFooter | Marca un elemento dentro de un hub-panel como banda de cabecera/pie de contenido del panel. Se renderiza en todas las vistas (tabs, pills, accordion, card), distinto de hubPanelHeading. | <hub-panel>
<div hubPanelHeader>Card title</div>
Card content
<div hubPanelFooter>Actions</div>
</hub-panel> |
type="card" | La visualización en tarjeta sin cromo: sin tira de navegación, todos los paneles siempre visibles. Un hub-panel también puede usarse de forma independiente, fuera de cualquier hub-panels, donde se renderiza como tarjeta. | <hub-panels type="card">
<hub-panel>…</hub-panel>
<hub-panel>…</hub-panel>
</hub-panels> |