Angular Tabs, Pills & Accordion | ng-hub-ui-panels
Angular content-panels component that renders as tabs, pills or an accordion, with routing, reactive forms, keyboard navigation and CSS variables.
API reference
Here's the full contract for panels: everything you can bind, listen to, project and theme, gathered in one place. Wire up what you need and style what you want — it's standalone and signal-friendly.
Inputs
Dial panels in with 29 inputs. Bind them like any Angular @Input.
| Name | Type | Default | Description |
|---|---|---|---|
type | 'tabs' | 'pills' | 'accordion' | 'card' | 'tabs' | Visualization of the container: underlined tabs, rounded pills or stacked accordion panels. |
vertical | boolean | false | Stacks the header strip vertically beside the content (tabs / pills views). |
justified | boolean | false | Stretches the headers to share the available width equally. |
scrollable | boolean | false | Adds backward/forward scroll buttons when the header strip overflows. |
isKeysAllowed | boolean | true | Enables keyboard navigation (arrows / Home / End / Delete). |
multiple | boolean | false | Allows several panels to be active at once. In the accordion view they all expand; in the tabs/pills views every active header starts a visible panel block and the following inactive headers stay grouped above that block until the next active header starts a new one. The form value becomes an array. |
flush | boolean | false | On <hub-panels> (accordion view): edge-to-edge panels without outer borders or radius. On <hub-panel> (card): removes the card body padding so a table/list/media block sits edge-to-edge. |
togglePosition | 'start' | 'end' | 'end' | On <hub-panels> (accordion view): which side of the header row the disclosure chevron sits on. "end" (default) trails the heading, "start" leads it. Only the visual order changes — the DOM is untouched — and the offsets are logical, so "start" is the left edge in LTR and the right edge in RTL. Set the app-wide default through PanelsConfig.togglePosition. |
bindValue | string | undefined | Dot-notation path applied to each panel's value to obtain the emitted form value (e.g. 'meta.key'). |
compareWith | (a: unknown, b: unknown) => boolean | (a, b) => a === b | Equality used to match form values against panel values. |
heading | string | undefined | hub-panel: plain-text header. Ignored when a hubPanelHeading template is provided. |
appearance | 'card' | 'alert' | 'card' | hub-panel: visual appearance of a standalone panel — 'card' (default) or a semantic 'alert' callout. Ignored in the tabs/pills/accordion strip views. |
variant | 'primary' | 'success' | 'danger' | 'warning' | 'info' | undefined | hub-panel: semantic colour of an alert ('primary' | 'success' | 'danger' | 'warning' | 'info'). Omit for a neutral alert. |
fill | boolean | false | Card panel only: fills the parent's height and lets the body scroll, so an inner flex:1/min-height:0 region (e.g. a tab strip + scroll pane) is bounded. The parent must be a flex column. |
standalone | boolean (static attribute) | false | Card panel only, static attribute: opts a loose <hub-panel> out of an ancestor tabs/pills/accordion group in the same template so it renders as a plain card instead of being captured as a hidden tab. |
value | unknown | id | hub-panel: value contributed when the container is used as a form control. |
active | boolean (model) | false | hub-panel: two-way bound active/expanded state. |
disabled | boolean | false | hub-panel: prevents the panel from being activated. |
removable | boolean | false | hub-panel: shows a ✕ affordance and enables removal with the Delete key. |
removeLabel | string | 'Remove panel' | hub-panel: accessible name (aria-label) announced for the ✕ remove button; override it to localize the control. |
routerLink | string | string[] | undefined | hub-panel: turns the panel into a routed panel backed by a <router-outlet>. |
queryParams | Params | undefined | hub-panel: query params appended when navigating to routerLink. |
pathMatch | 'route' | 'full' | 'route' | hub-panel: URL comparison used to mark a routed panel active. |
customClass | string | undefined | hub-panel: extra CSS classes applied to both the nav item and the pane. |
items | HubTabNavItem[] | [] | The selectable tabs of a <hub-tab-nav>, in render order. Each item is a lightweight { value, label, disabled?, id? } descriptor — the strip owns no content, so value is what it emits when the tab is chosen. |
active | unknown (model) | undefined | Two-way bound selected value of a <hub-tab-nav>. Set it to pre-select a tab and read it back through activeChange; the matching item is the value whose value equals this. |
appearance | 'tabs' | 'pills' | 'tabs' | Visual appearance of the <hub-tab-nav> strip: classic underlined 'tabs' (default) or rounded 'pills'. |
justified | boolean | false | When true, the <hub-tab-nav> tabs stretch to share the available width equally. |
vertical | boolean | false | When true, the <hub-tab-nav> strip stacks its tabs vertically instead of laying them out in a row. |
Outputs
React to what panels does — 5 events to hook your logic onto.
| Name | Type | Description |
|---|---|---|
panelChange | EventEmitter<PanelChangeEvent> | hub-panels: emitted when the user activates (opens) a different panel. Provides { current, prev }. |
selectPanel | EventEmitter<PanelComponent> | hub-panel: emitted when the panel becomes active. |
deselectPanel | EventEmitter<PanelComponent> | hub-panel: emitted when the panel stops being active. |
removed | EventEmitter<PanelComponent> | hub-panel: emitted when the panel is removed via the ✕ button or the Delete key. |
activeChange | EventEmitter<unknown> | Emitted by <hub-tab-nav> whenever the selected value changes (the change half of the two-way active model), carrying the newly selected item's value. |
Templates
Make it yours — 3 template slots let you project custom markup.
| Name | Description | Example |
|---|---|---|
hubPanelHeading | Marks an <ng-template> inside a hub-panel as that panel’s custom header (strip link in tabs/pills, disclosure button in accordion), replacing the plain-text heading input. | <hub-panel>
<ng-template hubPanelHeading>
<i class="fa-solid fa-gear"></i> Settings <span class="badge text-bg-primary">3</span>
</ng-template>
Panel content
</hub-panel> |
hubPanelHeader / hubPanelFooter | Mark an element inside a hub-panel as the panel’s content header/footer band. Renders in every view (tabs, pills, accordion, card), distinct from hubPanelHeading. | <hub-panel>
<div hubPanelHeader>Card title</div>
Card content
<div hubPanelFooter>Actions</div>
</hub-panel> |
type="card" | The chromeless card visualization: no navigation strip, every panel always visible. A hub-panel can also be used standalone, outside any hub-panels, where it renders as a card. | <hub-panels type="card">
<hub-panel>…</hub-panel>
<hub-panel>…</hub-panel>
</hub-panels> |