### File

`src/tabs/tab-header-group.component.ts`

### Implements

`AfterContentInit` `OnDestroy` `OnChanges`

### Metadata

selector | `ibm-tab-header-group`
template |
    <nav
    	class="bx--tabs"
    	[ngClass]="{
    		'bx--skeleton': skeleton
    	}"
    	role="navigation"
    	[attr.aria-label]="ariaLabel"
    	[attr.aria-labelledby]="ariaLabelledby">
    	<div
    		class="bx--tabs-trigger"
    		tabindex="0"
    		(click)="showTabList()"
    		(keydown)="onDropdownKeydown($event)">
    		<a
    			href="javascript:void(0)"
    			class="bx--tabs-trigger-text"
    			tabindex="-1">
    			<ng-container *ngIf="!getSelectedTab().headingIsTemplate">
    				{{ getSelectedTab().heading }}
    			</ng-container>
    			<ng-template
    				*ngIf="getSelectedTab().headingIsTemplate"
    				[ngTemplateOutlet]="getSelectedTab().heading"
    				[ngTemplateOutletContext]="{$implicit: getSelectedTab().context}">
    			</ng-template>
    		</a>
    		<svg width="10" height="5" viewBox="0 0 10 5">
    			<path d="M0 0l5 4.998L10 0z" fill-rule="evenodd"></path>
    		</svg>
    	</div>
    	<ul
    		#tabList
    		[ngClass]="{
    			'bx--tabs__nav--hidden': !tabListVisible
    		}"
    		(keydown)="tabDropdownKeydown($event)"
    		class="bx--tabs__nav"
    		role="tablist">
    		<li role="presentation">
    			<ng-container *ngIf="contentBefore" [ngTemplateOutlet]="contentBefore"></ng-container>
    		</li>
    		<ng-content></ng-content>
    		<li role="presentation">
    			<ng-container *ngIf="contentAfter" [ngTemplateOutlet]="contentAfter"></ng-container>
    		</li>
    	</ul>
    </nav>

### Index

###### Properties
Private _cacheActive Public currentSelectedIndex selectedSubscriptionTracker tabHeaderQuery Public tabListVisible
###### Methods
Public getSelectedTab ngAfterContentInit ngOnChanges ngOnDestroy Public onDropdownKeydown Public showTabList Public tabDropdownKeydown
###### Inputs
ariaLabel ariaLabelledby cacheActive contentAfter contentBefore followFocus skeleton
###### HostListeners
focusout keydown

### Constructor

`constructor(elementRef: ElementRef)`
Defined in src/tabs/tab-header-group.component.ts:113
Parameters :
Name | Type | Optional
elementRef | `ElementRef` | No

### Inputs

`ariaLabel` | Sets the aria label on the nav element. Type : `string`
Defined in src/tabs/tab-header-group.component.ts:82

`ariaLabelledby` | Sets the aria labelledby on the nav element. Type : `string`
Defined in src/tabs/tab-header-group.component.ts:86

`cacheActive` | Set to 'true' to have all pane references associated with each tab header in the tab header group cached and not reloaded on tab switching. Default value : `false`
Defined in src/tabs/tab-header-group.component.ts:96

`contentAfter` | Type : `TemplateRef<any>`
Defined in src/tabs/tab-header-group.component.ts:88

`contentBefore` | Type : `TemplateRef<any>`
Defined in src/tabs/tab-header-group.component.ts:90

`followFocus` | Set to 'true' to have tabs automatically activated and have their content displayed when they receive focus. Type : `boolean`
Defined in src/tabs/tab-header-group.component.ts:74

`skeleton` | Set to `true` to put tabs in a loading state. Default value : `false`
Defined in src/tabs/tab-header-group.component.ts:78

### HostListeners

focusout
Arguments : `'$event'`
`focusout(event)`
Defined in src/tabs/tab-header-group.component.ts:197

keydown
Arguments : `'$event'`
`keydown(event)`
Defined in src/tabs/tab-header-group.component.ts:122
Controls the keydown events used for tabbing through the headings.

### Methods

Public getSelectedTab
`getSelectedTab()`
Defined in src/tabs/tab-header-group.component.ts:235
Returns : `any`

ngAfterContentInit
`ngAfterContentInit()`
Defined in src/tabs/tab-header-group.component.ts:203
Returns : `void`

ngOnChanges
`ngOnChanges(changes: SimpleChanges)`
Defined in src/tabs/tab-header-group.component.ts:229
Parameters :
Name | Type | Optional
changes | `SimpleChanges` | No
Returns : `void`

ngOnDestroy
`ngOnDestroy()`
Defined in src/tabs/tab-header-group.component.ts:306
Returns : `void`

Public onDropdownKeydown
`onDropdownKeydown(event: KeyboardEvent)`
Defined in src/tabs/tab-header-group.component.ts:255
Parameters :
Name | Type | Optional
event | `KeyboardEvent` | No
Returns : `void`

Public showTabList
`showTabList()`
Defined in src/tabs/tab-header-group.component.ts:246
Returns : `void`

Public tabDropdownKeydown
`tabDropdownKeydown(event: KeyboardEvent)`
Defined in src/tabs/tab-header-group.component.ts:268
Parameters :
Name | Type | Optional
event | `KeyboardEvent` | No
Returns : `void`

### Properties

Private _cacheActive
`_cacheActive: ```
Default value : `false`
Defined in src/tabs/tab-header-group.component.ts:113

Public currentSelectedIndex
`currentSelectedIndex: `number``
Type : `number`
Default value : `0`
Defined in src/tabs/tab-header-group.component.ts:111
Controls the manual focusing done by tabbing through headings.

selectedSubscriptionTracker
`selectedSubscriptionTracker: ```
Default value : `new Subscription()`
Defined in src/tabs/tab-header-group.component.ts:105
Keeps track of all the subscriptions to the tab header selection events.

tabHeaderQuery
`tabHeaderQuery: `QueryList<TabHeader>``
Type : `QueryList<TabHeader>`
Decorators : `@ContentChildren(TabHeader)`
Defined in src/tabs/tab-header-group.component.ts:101
ContentChildren of all the tabHeaders.

Public tabListVisible
`tabListVisible: ```
Default value : `false`
Defined in src/tabs/tab-header-group.component.ts:107

    import {
    	Component,
    	QueryList,
    	Input,
    	HostListener,
    	ContentChildren,
    	OnDestroy,
    	AfterContentInit,
    	ElementRef,
    	TemplateRef,
    	OnChanges,
    	SimpleChanges
    } from "@angular/core";

    import { TabHeader } from "./tab-header.component";
    import { Subscription } from "rxjs";

    @Component({
    	selector: "ibm-tab-header-group",
    	template: `
    	<nav
    		class="bx--tabs"
    		[ngClass]="{
    			'bx--skeleton': skeleton
    		}"
    		role="navigation"
    		[attr.aria-label]="ariaLabel"
    		[attr.aria-labelledby]="ariaLabelledby">
    		<div
    			class="bx--tabs-trigger"
    			tabindex="0"
    			(click)="showTabList()"
    			(keydown)="onDropdownKeydown($event)">
    			<a
    				href="javascript:void(0)"
    				class="bx--tabs-trigger-text"
    				tabindex="-1">
    				<ng-container *ngIf="!getSelectedTab().headingIsTemplate">
    					{{ getSelectedTab().heading }}
    				</ng-container>
    				<ng-template
    					*ngIf="getSelectedTab().headingIsTemplate"
    					[ngTemplateOutlet]="getSelectedTab().heading"
    					[ngTemplateOutletContext]="{$implicit: getSelectedTab().context}">
    				</ng-template>
    			</a>
    			<svg width="10" height="5" viewBox="0 0 10 5">
    				<path d="M0 0l5 4.998L10 0z" fill-rule="evenodd"></path>
    			</svg>
    		</div>
    		<ul
    			#tabList
    			[ngClass]="{
    				'bx--tabs__nav--hidden': !tabListVisible
    			}"
    			(keydown)="tabDropdownKeydown($event)"
    			class="bx--tabs__nav"
    			role="tablist">
    			<li role="presentation">
    				<ng-container *ngIf="contentBefore" [ngTemplateOutlet]="contentBefore"></ng-container>
    			</li>
    			<ng-content></ng-content>
    			<li role="presentation">
    				<ng-container *ngIf="contentAfter" [ngTemplateOutlet]="contentAfter"></ng-container>
    			</li>
    		</ul>
    	</nav>
    	`
    })
    export class TabHeaderGroup implements AfterContentInit, OnDestroy, OnChanges {
    	/**
    	 * Set to 'true' to have tabs automatically activated and have their content displayed when they receive focus.
    	 */
    	@Input() followFocus: boolean;
    	/**
    	 * Set to `true` to put tabs in a loading state.
    	 */
    	@Input() skeleton = false;
    	/**
    	 * Sets the aria label on the nav element.
    	 */
    	@Input() ariaLabel: string;
    	/**
    	 * Sets the aria labelledby on the nav element.
    	 */
    	@Input() ariaLabelledby: string;

    	@Input() contentAfter: TemplateRef<any>;

    	@Input() contentBefore: TemplateRef<any>;

    	/**
    	 * Set to 'true' to have all pane references associated with each tab header
    	 * in the tab header group cached and not reloaded on tab switching.
    	 */
    	@Input() cacheActive = false;

    	/**
    	 * ContentChildren of all the tabHeaders.
    	 */
    	@ContentChildren(TabHeader) tabHeaderQuery: QueryList<TabHeader>;
    	/**
    	 * Keeps track of all the subscriptions to the tab header selection events.
    	 */
    	selectedSubscriptionTracker = new Subscription();

    	public tabListVisible = false;
    	/**
    	 * Controls the manual focusing done by tabbing through headings.
    	 */
    	public currentSelectedIndex = 0;

    	private _cacheActive = false;

    	constructor(protected elementRef: ElementRef) {}

    	// keyboard accessibility
    	/**
    	 * Controls the keydown events used for tabbing through the headings.
    	 */
    	@HostListener("keydown", ["$event"])
    	keyboardInput(event) {
    		let tabHeadersArray = Array.from<any>(this.tabHeaderQuery);

    		if (event.key === "Right" || event.key === "ArrowRight") {
    			if (this.currentSelectedIndex < tabHeadersArray.length - 1) {
    				event.preventDefault();
    				if (this.followFocus && !tabHeadersArray[this.currentSelectedIndex + 1].disabled) {
    					tabHeadersArray[this.currentSelectedIndex + 1].selectTab();
    				} else {
    					tabHeadersArray[this.currentSelectedIndex + 1].tabItem.nativeElement.focus();
    					this.currentSelectedIndex++;
    				}
    			} else {
    				event.preventDefault();
    				if (this.followFocus && !tabHeadersArray[0].disabled) {
    					tabHeadersArray[0].selectTab();
    				} else {
    					tabHeadersArray[0].tabItem.nativeElement.focus();
    					this.currentSelectedIndex = 0;
    				}
    			}
    		}

    		if (event.key === "Left" || event.key === "ArrowLeft") {
    			if (this.currentSelectedIndex > 0) {
    				event.preventDefault();
    				if (this.followFocus && !tabHeadersArray[this.currentSelectedIndex - 1].disabled) {
    					tabHeadersArray[this.currentSelectedIndex - 1].selectTab();
    				} else {
    					tabHeadersArray[this.currentSelectedIndex - 1].tabItem.nativeElement.focus();
    					this.currentSelectedIndex--;
    				}
    			} else {
    				event.preventDefault();
    				if (this.followFocus && !tabHeadersArray[tabHeadersArray.length - 1].disabled) {
    					tabHeadersArray[tabHeadersArray.length - 1].selectTab();
    				} else {
    					tabHeadersArray[tabHeadersArray.length - 1].tabItem.nativeElement.focus();
    					this.currentSelectedIndex = tabHeadersArray.length - 1;
    				}
    			}
    		}

    		if (event.key === "Home") {
    			event.preventDefault();
    			if (this.followFocus && !tabHeadersArray[0].disabled) {
    				tabHeadersArray[0].selectTab();
    			} else {
    				tabHeadersArray[0].tabItem.nativeElement.focus();
    				this.currentSelectedIndex = 0;
    			}
    		}

    		if (event.key === "End") {
    			event.preventDefault();
    			if (this.followFocus && !tabHeadersArray[tabHeadersArray.length - 1].disabled) {
    				tabHeadersArray[tabHeadersArray.length - 1].selectTab();
    			} else {
    				tabHeadersArray[tabHeadersArray.length - 1].tabItem.nativeElement.focus();
    				this.currentSelectedIndex = tabHeadersArray.length - 1;
    			}
    		}

    		// `"Spacebar"` is IE11 specific value
    		if ((event.key === " " || event.key === "Spacebar") && !this.followFocus) {
    			tabHeadersArray[this.currentSelectedIndex].selectTab();
    		}

    		// dropdown list handler
    		if (event.key === "Escape") {
    			this.tabListVisible = false;
    		}
    	}

    	@HostListener("focusout", ["$event"])
    	focusOut(event) {
    		if (this.tabListVisible && !this.elementRef.nativeElement.contains(event.relatedTarget)) {
    			this.tabListVisible = false;
    		}
    	}

    	ngAfterContentInit() {
    		this.selectedSubscriptionTracker.unsubscribe();

    		if (this.tabHeaderQuery) {
    			this.tabHeaderQuery.toArray().forEach(tabHeader => tabHeader.cacheActive = this.cacheActive);
    		}

    		const selectedSubscriptions = this.tabHeaderQuery.toArray().forEach(tabHeader => {
    			tabHeader.selected.subscribe(() => {
    				this.currentSelectedIndex = this.tabHeaderQuery.toArray().indexOf(tabHeader);
    				// The Filter takes the current selected tab out, then all other headers are
    				// deactivated and their associated pane references are also deactivated.
    				this.tabHeaderQuery.toArray().filter(header => header !== tabHeader)
    					.forEach(filteredHeader => {
    						filteredHeader.active = false;
    						if (filteredHeader.paneReference) {
    							filteredHeader.paneReference.active = false;
    						}
    					});
    			});
    		});
    		this.selectedSubscriptionTracker.add(selectedSubscriptions);

    		this.tabHeaderQuery.toArray()[this.currentSelectedIndex].selectTab();
    	}

    	ngOnChanges(changes: SimpleChanges) {
    		if (this.tabHeaderQuery && changes.cacheActive) {
    			this.tabHeaderQuery.toArray().forEach(tabHeader => tabHeader.cacheActive = this.cacheActive);
    		}
    	}

    	public getSelectedTab(): any {
    		const selected =  this.tabHeaderQuery.toArray()[this.currentSelectedIndex];
    		if (selected) {
    			return selected;
    		}
    		return {
    			headingIsTemplate: false,
    			heading: ""
    		};
    	}

    	public showTabList() {
    		this.tabListVisible = true;
    		const focusTarget = this.tabHeaderQuery.toArray().find(tab => {
    			const tabContainer = tab.tabItem.nativeElement.parentElement;
    			return !tabContainer.classList.contains("bx--tabs__nav-item--selected");
    		});
    		focusTarget.tabItem.nativeElement.focus();
    	}

    	public onDropdownKeydown(event: KeyboardEvent) {
    		switch (event.key) {
    			case " ":
    			case "Spacebar":
    			case "Enter":
    				event.preventDefault();
    				this.showTabList();
    				break;
    			default:
    				break;
    		}
    	}

    	public tabDropdownKeydown(event: KeyboardEvent) {
    		if (!this.tabListVisible) { return; }

    		const target = (event.target as HTMLElement).closest("a");

    		const headers = this.tabHeaderQuery.toArray().filter(tab =>
    			!tab.tabItem.nativeElement.parentElement.classList.contains("bx--tabs__nav-item--disabled") &&
    			!tab.tabItem.nativeElement.parentElement.classList.contains("bx--tabs__nav-item--selected"));

    		// unless focus can move, it should remain on the target
    		let next: HTMLElement = target;
    		let previous: HTMLElement = target;

    		for (let i = 0; i < headers.length; i++) {
    			if (headers[i].tabItem.nativeElement === target) {
    				if (i + 1 < headers.length) {
    					next = headers[i + 1].tabItem.nativeElement;
    				}
    				if (i - 1 >= 0) {
    					previous = headers[i - 1].tabItem.nativeElement;
    				}
    			}
    		}

    		switch (event.key) {
    			case "ArrowDown":
    			case "Down": // IE11 specific value
    				next.focus();
    				break;
    			case "ArrowUp":
    			case "Up": // IE11 specific value
    				previous.focus();
    				break;
    			default:
    				break;
    		}
    	}

    	ngOnDestroy() {
    		this.selectedSubscriptionTracker.unsubscribe();
    	}
    }

Legend
Html element
Component
Html element with directive

# result-matching ""

# No results matching ""