# API of `@koobiq/components/tabs`

Documented on [Tabs](https://koobiq.io/en/components/tabs.md). NgModule: `KbqTabsModule`.

## Components

### KbqTab (component)

```ts
@Component({ selector: 'kbq-tab', exportAs: 'kbqTab' })
class KbqTab {
    tooltipTitle = input<string | undefined>();
    disabled = input<boolean | undefined>();
    readonly tooltipPlacement = input<KbqPopUpPlacementValues>(
        PopUpPlacements.Right
    );
    readonly textLabel = input<string>('', { alias: 'label' });
    readonly empty = input<boolean>(false);
    readonly tabId = input<string>();
    templateLabel: KbqTabLabel;
    readonly explicitContent: Signal<TemplateRef<any> | undefined>;
    readonly implicitContent: Signal<TemplateRef<any>>;
    get iconOnlyLabel(): boolean;
    readonly stateChanges: Subject<void>;
    position: number | null;
    origin: number | null;
    isActive: boolean;
    get isOverflown(): boolean;
    overflowTooltipTitle: string;
}
```

- `[disabled]`: `boolean | undefined` — Whether the tab is disabled: it cannot be selected and has no interactive states.
- `[tooltipPlacement]`: `KbqPopUpPlacementValues` — Placement of the tooltip shown for a truncated or empty label.
- `[label]`: `string` — Plain text label for the tab, used when there is no template label.
- `templateLabel`: `KbqTabLabel` — The label template of the tab: the `kbqTabLabel` in its content, or else the one assigned in code.
- `explicitContent`: `Signal<TemplateRef<any> | undefined>` — Template provided in the tab content that will be used if present, used to enable lazy-loading
- `implicitContent`: `Signal<TemplateRef<any>>` — Template inside the KbqTab view that contains an `<ng-content>`.
- `iconOnlyLabel`: `boolean` — Whether the tab label contains only an icon (no text).
- `stateChanges`: `Subject<void>` — Emits whenever the internal state of the tab changes.
- `position`: `number | null` — The relatively indexed position where 0 represents the center, negative is left, and positive
  represents the right.
- `origin`: `number | null` — The initial relatively index origin of the tab if it was created and selected after there
  was already a selected tab. Provides context of what position the tab should originate from.
- `isActive`: `boolean` — Whether the tab is currently active. A template that reads it is updated when it changes.

### KbqTabGroup (component)

Tab-group component.  Supports basic tab pairs (label + content) and includes keyboard navigation.

```ts
@Component({ selector: 'kbq-tab-group', exportAs: 'kbqTabGroup' })
class KbqTabGroup {
    readonly transparent = input<boolean>(false);
    readonly onSurface = input<boolean>(false);
    readonly underlined = input<boolean>(false);
    readonly vertical = input<boolean>(false);
    readonly dynamicHeight = input<boolean>(false);
    selectedIndex = model<number | undefined>();
    activeTab = model<KbqTabSelectBy | null | undefined>();
    headerPosition = input<KbqTabHeaderPosition | undefined>();
    animationDuration = input<string | undefined>();
    readonly focusChange = output<KbqTabChangeEvent>();
    readonly animationDone = output<void>();
    readonly selectedTabChange = output<KbqTabChangeEvent>();
    get tabs(): QueryList<KbqTab>;
    readonly tabBodyWrapper: Signal<ElementRef<any>>;
    readonly tabHeader: Signal<KbqTabHeader>;
    get hasSavedState(): boolean;
    focusChanged(index: number): void;
    getTabLabelId(i: number): string;
    getTabContentId(i: number): string;
    setTabBodyWrapperHeight(tabHeight: number): void;
    removeTabBodyWrapperHeight(): void;
    handleClick(
        tab: KbqTab,
        tabHeader: KbqTabHeader,
        index: number
    ): void;
    getTabIndex(
        tab: KbqTab,
        tabHeader: KbqTabHeader,
        index: number
    ): number;
    onSelectFocusedIndex($event: number): void;
    saveState(): void;
    clearSavedState(): void;
}
```

- `[transparent]`: `boolean` — Whether the tab strip background should be transparent.
- `[onSurface]`: `boolean` — Whether the group is rendered on a surface rather than on the page background.
- `[underlined]`: `boolean` — Whether the selected tab is marked with an underline instead of a filled background.
- `[vertical]`: `boolean` — Whether the tab strip is laid out vertically, alongside the content instead of above it.
- `[dynamicHeight]`: `boolean` — Whether the tab group should grow to the size of the active tab.
- `[(selectedIndex)]`: `number | undefined` — The index of the active tab.
- `[headerPosition]`: `KbqTabHeaderPosition | undefined` — Position of the tab header.
- `[animationDuration]`: `string | undefined` — Duration for the tab animation. Must be a valid CSS value (e.g. 600ms).
- `[useStateSaving]`: `boolean` — Whether the component remembers its state across reloads and restores it on the next render.
  Defaults to `true`, or to whatever `KBQ_STATE_SAVING_ENABLED` is provided as.
- `[stateSavingKey]`: `string` — The key the state is persisted under. While it is empty the key is derived from where the
  component sits in the document, which moves when the surrounding markup is restructured — an `id`
  on the component or any ancestor pins it just as well as this input does.
- `(focusChange)`: `KbqTabChangeEvent` — Event emitted when focus has changed within a tab group.
- `(animationDone)`: `void` — Event emitted when the body animation has completed
- `(selectedTabChange)`: `KbqTabChangeEvent` — Event emitted when the tab selection has changed.
- `tabs`: `QueryList<KbqTab>` — The tabs of the group.
- `hasSavedState`: `boolean` — Whether state is currently persisted for this tab group — restored on init, or written since.
  Always `false` while `useStateSaving` is unset, and `false` again after `clearSavedState()`.
- `getTabLabelId()`: `string` — Returns a unique id for each tab label element
- `getTabContentId()`: `string` — Returns a unique id for each tab content element
- `setTabBodyWrapperHeight()`: `void` — Sets the height of the body wrapper to the height of the activating tab if dynamic
  height property is true.
- `removeTabBodyWrapperHeight()`: `void` — Removes the height of the tab body wrapper.
- `handleClick()`: `void` — Handle click events, setting new selected index if appropriate.
- `getTabIndex()`: `number` — Retrieves the tabindex for the tab. The single `0` follows the header's focus position rather
  than the selection, so that a disabled selected tab cannot take the whole strip out of the tab
  order — a disabled tab is `-1`, never absent, so it stays a roving-tabindex participant.
- `saveState()`: `void` — Persists which tab is selected.

  Called for every selection a user makes. Both the tab's `tabId` and its position are stored: the
  `tabId` is the only one that survives the tabs being reordered, and the position is all there is
  when the tabs carry none.
- `clearSavedState()`: `void` — Removes the state persisted for this tab group.

  Persistence itself stays on — the next selection is written again. Unset `useStateSaving` to stop
  it.

### KbqTabNavBar (component)

Navigation component matching the styles of the tab group header.

```ts
@Component({
    selector: '[kbqTabNavBar], [kbq-tab-nav-bar]',
    exportAs: 'kbqTabNavBar'
})
class KbqTabNavBar extends KbqPaginatedTabHeader {
    readonly transparent = input<boolean>(false);
    readonly onSurface = input<boolean>(false);
    readonly underlined = input<boolean>(false);
    readonly tabNavPanel = input<KbqTabNavPanel>();
    selectedIndex = input<number | undefined>();
    disablePagination = input<boolean | undefined>();
    vertical = input<boolean | undefined>();
    get tabListContainer(): ElementRef;
    get tabList(): ElementRef;
    get nextPaginator(): ElementRef<HTMLElement>;
    get previousPaginator(): ElementRef<HTMLElement>;
    get items(): QueryList<KbqTabLink>;
    get role(): string | null;
    focusIndex: number;
    readonly selectFocusedIndex: EventEmitter<number>;
    readonly indexFocused: EventEmitter<number>;
    showPaginationControls: boolean;
    disableScrollAfter: boolean;
    disableScrollBefore: boolean;
    readonly elementRef: ElementRef<HTMLElement>;
    updateActiveLink(): void;
    handleKeydown(event: KeyboardEvent): void;
    onContentChanges(): void;
    updatePagination(): void;
    isValidIndex(index: number): boolean;
    setTabFocus(tabIndex: number): void;
    getLayoutDirection(): Direction;
    scrollHeader(direction: ScrollDirection): void;
    handlePaginatorClick(direction: ScrollDirection): void;
    checkPaginationEnabled(): void;
    stopInterval(): void;
    handlePaginatorPress(
        direction: ScrollDirection,
        mouseEvent?: MouseEvent
    ): void;
}
```

- `[transparent]`: `boolean` — Whether the nav bar background should be transparent.
- `[underlined]`: `boolean` — Whether the nav bar should be underlined.
- `[tabNavPanel]`: `KbqTabNavPanel` — Associated tab panel controlled by the nav bar.
- `[selectedIndex]`: `number | undefined` — The index of the active tab.
- `[disablePagination]`: `boolean | undefined` — Whether pagination should be disabled. This can be used to avoid unnecessary
  layout recalculations if it's known that pagination won't be required.

  A vertical header never paginates, so `vertical` forces this on without overwriting the value
  the consumer set — turning `vertical` back off restores it.
- `[vertical]`: `boolean | undefined` — Whether the tabs should be displayed vertically.
- `tabListContainer`: `ElementRef` — The scroll container of the tab links.
- `tabList`: `ElementRef` — The element that holds the tab links.
- `nextPaginator`: `ElementRef<HTMLElement>` — The pagination arrow towards the end of the tab list.
- `previousPaginator`: `ElementRef<HTMLElement>` — The pagination arrow towards the beginning of the tab list.
- `items`: `QueryList<KbqTabLink>` — The tab links of the nav bar.
- `focusIndex`: `number` — Tracks which element has focus; used for keyboard navigation
- `selectFocusedIndex`: `EventEmitter<number>` — Event emitted when the option is selected.
- `indexFocused`: `EventEmitter<number>` — Event emitted when a label is focused.
- `showPaginationControls`: `boolean` — Whether the controls for pagination should be displayed
- `disableScrollAfter`: `boolean` — Whether the tab list can be scrolled more towards the end of the tab label list.
- `disableScrollBefore`: `boolean` — Whether the tab list can be scrolled more towards the beginning of the tab label list.
- `updateActiveLink()`: `void` — Notifies the component that the active link has been changed.
- `onContentChanges()`: `void` — Callback for when the MutationObserver detects that the content has changed.
- `updatePagination()`: `void` — Updates the view whether pagination should be enabled or not.

  WARNING: Calling this method can be very costly in terms of performance. It should be called
  as infrequently as possible from outside of the Tabs component as it causes a reflow of the
  page.
- `isValidIndex()`: `boolean` — Determines if an index is valid.  If the tabs are not ready yet, we assume that the user is
  providing a valid index and return true.
- `setTabFocus()`: `void` — Sets focus on the HTML element for the label wrapper and scrolls it into the view if
  scrolling is enabled.
- `getLayoutDirection()`: `Direction` — The layout direction of the containing app.
- `scrollHeader()`: `void` — Moves the tab list in the 'before' or 'after' direction (towards the beginning of the list or
  the end of the list, respectively).

  This is an expensive call that forces a layout reflow to compute box and scroll metrics and
  should be called sparingly.
- `handlePaginatorClick()`: `void` — Handles click events on the pagination arrows.
- `checkPaginationEnabled()`: `void` — Evaluate whether the pagination controls should be displayed. If the scroll width of the
  tab list is wider than the size of the header container, then the pagination controls should
  be shown.

  This is an expensive call that forces a layout reflow to compute box and scroll metrics and
  should be called sparingly.
- `stopInterval()`: `void` — Stops the currently-running paginator interval.
- `handlePaginatorPress()`: `void` — Handles the user pressing down on one of the paginators.
  Starts scrolling the header after a certain amount of time.
  - `direction`: `ScrollDirection` — In which direction the paginator should be scrolled.

## Directives

### KbqAlignTabsCenterCssStyler (directive)

```ts
@Directive({
    selector: 'kbq-tab-group[kbq-align-tabs-center], [kbq-tab-nav-bar][kbq-align-tabs-center], [kbqTabNavBar][kbq-align-tabs-center]'
})
class KbqAlignTabsCenterCssStyler {}
```

### KbqAlignTabsEndCssStyler (directive)

```ts
@Directive({
    selector: 'kbq-tab-group[kbq-align-tabs-end], [kbq-tab-nav-bar][kbq-align-tabs-end], [kbqTabNavBar][kbq-align-tabs-end]'
})
class KbqAlignTabsEndCssStyler {}
```

### KbqStretchTabsCssStyler (directive)

```ts
@Directive({
    selector: 'kbq-tab-group[kbq-stretch-tabs], [kbq-tab-nav-bar][kbq-stretch-tabs], [kbqTabNavBar][kbq-stretch-tabs]'
})
class KbqStretchTabsCssStyler {}
```

### KbqTabContent (directive)

Decorates the `ng-template` tags and reads out the template from it.

```ts
@Directive({ selector: '[kbqTabContent]' })
class KbqTabContent {
    template: TemplateRef<any>;
}
```

### KbqTabLabel (directive)

Used to flag tab labels for use with the portal directive

```ts
@Directive({ selector: '[kbq-tab-label], [kbqTabLabel]' })
class KbqTabLabel extends CdkPortal {
    readonly iconOnly = input<boolean>(false);
    templateRef: TemplateRef<C>;
    viewContainerRef: ViewContainerRef;
    context?: C;
    injector?: Injector;
    get origin(): ElementRef<any>;
    get isAttached(): boolean;
    attach(host: PortalOutlet, context?: C): EmbeddedViewRef<C>;
    detach(): void;
    setAttachedHost(host: PortalOutlet | null): void;
}
```

- `[iconOnly]`: `boolean` — Whether the tab contains only an icon without a label.
- `templateRef`: `TemplateRef<C>` — The embedded template that will be used to instantiate an embedded View in the host.
- `viewContainerRef`: `ViewContainerRef` — Reference to the ViewContainer into which the template will be stamped out.
- `context?`: `C` — Contextual data to be passed in to the embedded view.
- `injector?`: `Injector` — The injector to use for the embedded view.
- `isAttached`: `boolean` — Whether this portal is attached to a host.
- `attach()`: `EmbeddedViewRef<C>` — Attach the portal to the provided `PortalOutlet`.
  When a context is provided it will override the `context` property of the `TemplatePortal`
  instance.
- `setAttachedHost()`: `void` — Sets the PortalOutlet reference without performing `attach()`. This is used directly by
  the PortalOutlet when it is performing an `attach()` or `detach()`.

### KbqTabLink (directive)

Link inside of a KbqTabNavBar.

```ts
@Directive({ selector: '[kbqTabLink], [kbq-tab-link]', exportAs: 'kbqTabLink' })
class KbqTabLink {
    id = input<string | undefined>();
    active = input<boolean | undefined>();
    disabled = input<boolean | undefined>();
    get vertical(): boolean;
    get underlined(): boolean;
    readonly elementRef: ElementRef<HTMLElement>;
    focus(): void;
}
```

- `[id]`: `string | undefined` — Unique id for the link.
- `[active]`: `boolean | undefined` — Whether the link is active.
- `[disabled]`: `boolean | undefined` — Whether the tab link is disabled.
- `focus()`: `void` — Focuses the tab link.

  `preventScroll: true`: `FocusKeyManager.setActiveItem` calls this itself, right after (and
  unconditionally on) the `change` emission that runs `KbqPaginatedTabHeader.setTabFocus` — so
  without the guard here too, that call's own `preventScroll: true` is immediately undone by
  this one, and an overflowing nav bar double-jumps (native scroll-into-view, then the
  paginator-aware `scrollCorrection`) on every arrow-key press.

### KbqTabNavPanel (directive)

Tab panel component associated with KbqTabNav.

```ts
@Directive({ selector: '[kbqTabNavPanel]', exportAs: 'kbqTabNavPanel' })
class KbqTabNavPanel {
    readonly id = input<string>(`kbq-tab-nav-panel-${nextUniqueId++}`);
    activeTabId?: string;
}
```

- `[id]`: `string` — Unique id for the tab panel.
- `activeTabId?`: `string` — Id of the active tab in the nav bar.

### KbqVerticalTabsCssStyler (directive)

Deprecated: No-op. The vertical layout class is bound from `KbqTabGroup`/`KbqTabNavBar` themselves,
so it follows the `vertical` value instead of merely the presence of the attribute. Will be removed
in a future major version — stop importing it.

```ts
@Directive({
    selector: 'kbq-tab-group[vertical], [kbq-tab-nav-bar][vertical], [kbqTabNavBar][vertical]'
})
class KbqVerticalTabsCssStyler {}
```

## Classes

### KbqTabChangeEvent (class)

A simple change event emitted on focus or selection changes.

```ts
class KbqTabChangeEvent {
    index: number;
    tab: KbqTab;
}
```

- `index`: `number` — Index of the currently-selected tab.
- `tab`: `KbqTab` — Reference to the currently-selected tab.

## Types

### KbqPaginatedTabHeaderItem (type)

Item inside a paginated tab header.

```ts
type KbqPaginatedTabHeaderItem = FocusableOption & {
    elementRef: ElementRef;
};
```

### KbqTabBodyPositionState (type)

These position states are used internally as the translation states of the tab body. Setting the
position state to left, right, or center will transition the tab body from its current
position to its respective state. If there is not current position (void, in the case of a new
tab body), then there will be no transition to its state.

In the case of a new tab body that should immediately be centered with an animating transition,
then left-origin-center or right-origin-center can be used, which will use left or right as its
pseudo-prior state.

```ts
type KbqTabBodyPositionState = 'left' | 'center' | 'right' | 'left-origin-center' | 'right-origin-center';
```

### KbqTabHeaderPosition (type)

Possible positions for the tab header.

```ts
type KbqTabHeaderPosition = 'above' | 'below';
```

### KbqTabsConfig (interface)

Object that can be used to configure the default options for the tabs module.

```ts
interface KbqTabsConfig {
    animationDuration?: string;
}
```

- `animationDuration?`: `string` — Duration for the tab animation. Must be a valid CSS value (e.g. 600ms).

### KbqTabSelectBy (type)

```ts
type KbqTabSelectBy = string | number | ((tabs: KbqTab[]) => KbqTab | null);
```

### KbqTabsState (interface)

The persisted state of a tab group — which tab was selected.

Both are stored: `tabId` is the only identifier that survives a reordering, and `index` is all there is
when the tabs carry no `tabId`.

```ts
interface KbqTabsState {
    tabId: string | null;
    index: number;
}
```

### ScrollDirection (type)

The directions that scrolling can go in when the header's tabs exceed the header width. 'After'
will scroll the header towards the end of the tabs list and 'before' will scroll towards the
beginning of the list.

```ts
type ScrollDirection = 'after' | 'before';
```

## Constants

### KBQ_TAB_LABEL (const)

```ts
const KBQ_TAB_LABEL: InjectionToken<KbqTabLabel>;
```

### KBQ_TABS_CONFIG (const)

Injection token that can be used to provide the default options the tabs module.

```ts
const KBQ_TABS_CONFIG: InjectionToken<KbqTabsConfig>;
```
