# TabPanel 101

This page shows how to get started with Wijmo's TabPanel control.

## Getting Started

Steps for getting started with TabPanel in Angular applications:

1. Add references to Angular, Wijmo, and Wijmo for Angular components.
2. Add a component to provide data and logic.
3. Add wj-tab-panel with nested wj-tab components to the component template.
4. Add some CSS to customize the TabPanel's appearance.

The markup used to initialize TabPanel controls consists of one wj-tab-panel element with nested wj-tab elements, one element per tab. Each wj-tab element contains two children: the tab header and the tab content.

We suggest you use anchor elements (tag a) for the tab headers because they are semantically more meaningful than plain div elements.

In this example, we use the TabPanel's selectedIndex property to define the initially selected tab.

HTML
<!DOCTYPE html> <html> <head> <!-- Supporting libraries --> <!-- Polyfill(s) for older browsers --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/reflect-metadata/Reflect.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <!-- Configure SystemJS --> <script src="systemjs.config.js"></script> <!-- Bootstrap --> <link rel="stylesheet" type="text/css" href="bin/Devel/external/bootstrap/css/bootstrap.css" /> <!-- Wijmo --> <link href="bin/Devel/sources/styles/wijmo.css" rel="stylesheet" /> <!-- Configure and load application --> <link href="src/styles/app.css" rel="stylesheet" /> <!-- Load the root application module --> <script> System.import('./src/app'); </script> </head> <body> <!-- Add root application component --> <app-cmp></app-cmp> </body> </html> <!-- Root application component's template (app.html) --> <wj-tab-panel [selectedIndex]="1"> <wj-tab> <a>Africa</a> <div> <ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> <li>Botswana</li> </ul> </div> </wj-tab> <wj-tab> <a> America </a> <div> <ul> <li>Canada</li> <li>Chile</li> <li>Mexico</li> <li>United States</li> </ul> </div> </wj-tab> <wj-tab> <a>Asia</a> <div> <ul> <li>China</li> <li>Korea</li> <li>India</li> <li>Japan</li> </ul> </div> </wj-tab> <wj-tab> <a>Europe</a> <div> <ul> <li>Austria</li> <li>England</li> <li>France</li> <li>Germany</li> <li>Netherlands</li> <li>Switzerland</li> </ul> </div> </wj-tab> <wj-tab> <a>Oceania</a> <div> <ul> <li>Australia</li> <li>Fiji</li> <li>New Zealand</li> <li>Samoa</li> </ul> </div> </wj-tab> </wj-tab-panel>
TS
// Angular import { Component, EventEmitter, Input, Inject, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { WjNavModule} from 'wijmo/wijmo.angular2.nav'; 'use strict'; // The application root component. @Component({ selector: 'app-cmp', templateUrl: 'src/app.html', }) export class AppCmp { constructor() { } } @NgModule({ imports: [WjNavModule, BrowserModule, FormsModule], declarations: [AppCmp], providers: [], bootstrap: [AppCmp] }) export class AppModule { } enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule);

#### Result (live):

Africa

- Algeria
- Angola
- Benin
- Botswana

America

- Canada
- Chile
- Mexico
- United States

Asia

- China
- Korea
- India
- Japan

Europe

- Austria
- England
- France
- Germany
- Netherlands
- Switzerland

Oceania

- Australia
- Fiji
- New Zealand
- Samoa

## Hosting Wijmo Controls

One of the main benefits of the TabPanel control is that it automatically updates any Wijmo controls it contains when a new tab is selected.

When using other tab controls, you must add code to refresh any Wijmo controls contained in the tabs.

HTML
<wj-tab-panel> <wj-tab> <a>FlexGrid</a> <div> <wj-flex-grid [itemsSource]="data"> </wj-flex-grid> </div> </wj-tab> <wj-tab> <a>FlexChart</a> <div> <wj-flex-chart [itemsSource]="data" [bindingX]="'country'"> <wj-flex-chart-series [name]="'Sales'" [binding]="'sales'"></wj-flex-chart-series> <wj-flex-chart-series [name]="'Expenses'" [binding]="'expenses'"></wj-flex-chart-series> <wj-flex-chart-series [name]="'Downloads'" [binding]="'downloads'"></wj-flex-chart-series> </wj-flex-chart> </div> </wj-tab> <wj-tab> <a>Gauges</a> <div style="overflow:hidden"> <wj-radial-gauge style="display:block" [value]="75" [min]="0" [isReadOnly]="false" [max]="100"> </wj-radial-gauge> <wj-linear-gauge style="display:block" [value]="75" [min]="0" [isReadOnly]="false" [max]="100"> </wj-linear-gauge> </div> </wj-tab> </wj-tab-panel>
TS
export class AppCmp { data: any; constructor() { this.data = this._getData(); } // data used to generate random items private _getData(): any { var countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (var i = 0; i < countries.length; i++) { data.push({ country: countries[i], sales: Math.random() * 10000, expenses: Math.random() * 5000, downloads: Math.round(Math.random() * 20000), }); } return data; } }
CSS
.wj-tabpanel .wj-flexgrid, .wj-tabpanel .wj-flexchart, .wj-tabpanel .wj-radialgauge { height: 200px; border: none; }

#### Result (live):

FlexGrid
FlexChart
Gauges

## Dynamic Tabs

You may want your tab list and tabs content to be driven by data stored in an array.

This can be achieved by adding the ngFor directive bound to an array with information about tabs, to the wj-tab element.

In this example, we bind tabs to an array containing information about tab header, content data, and enabled state.

HTML
<wj-tab-panel #pTabPanel [selectedIndex]="0"> <wj-tab *ngFor="let tab of tabsInfo" [isDisabled]="!tab.isEnabled"> <a>{{tab.header}}</a> <div> <wj-flex-grid [isReadOnly]="true" [itemsSource]="tab.data"> </wj-flex-grid> </div> </wj-tab> </wj-tab-panel>
TS
export class AppCmp { tabsInfo: any[]; constructor() { this._initTabsInfo(); } private _initTabsInfo() { let headers = 'Employees,Categories,Products,Customers'.split(','), url = 'http://services.odata.org/Northwind/Northwind.svc/'; this.tabsInfo = []; headers.forEach((header) => { this.tabsInfo.push({ header: header, data: new wjcOdata.ODataCollectionView(url, header), isEnabled: header != 'Products' }); }) } }

#### Result (live):

{{tab.header}}

## Styling and CSS

You can customize the appearance of the TabPanel using CSS.

The TabPanel control has a simple layout, which makes it easy to style using CSS. For example, tabs appear above the content by default, but you can use CSS to change their position and show the below or vertically stacked, to the left or to the right of the content.

This example changes the appearance of the Tabs and lets you select the tab alignment and whether or not to use animation when switching tabs.

HTML
<wj-tab-panel #tabCss class="custom-tab" [(isAnimated)]="isAnimated"> <wj-tab> <a>Africa</a> <div> <ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> <li>Botswana</li> </ul> </div> </wj-tab> <wj-tab> <a> America </a> <div> <ul> <li>Canada</li> <li>Chile</li> <li>Mexico</li> <li>United States</li> </ul> </div> </wj-tab> <wj-tab> <a>Asia</a> <div> <ul> <li>China</li> <li>Korea</li> <li>India</li> <li>Japan</li> </ul> </div> </wj-tab> <wj-tab> <a>Europe</a> <div> <ul> <li>Austria</li> <li>England</li> <li>France</li> <li>Germany</li> <li>Netherlands</li> <li>Switzerland</li> </ul> </div> </wj-tab> <wj-tab> <a>Oceania</a> <div> <ul> <li>Australia</li> <li>Fiji</li> <li>New Zealand</li> <li>Samoa</li> </ul> </div> </wj-tab> </wj-tab-panel> <div> <label for="tabAlign"> Tab Alignment </label> <wj-combo-box #cmbTabAlign [itemsSource]="tabAligns" (selectedIndexChanged)="tabAlignChanged(cmbTabAlign, tabCss)"> </wj-combo-box> </div> <div> <label for="isAnimated"> isAnimated </label> <input id="isAnimated" type="checkbox" checked="checked" [(ngModel)]="isAnimated"> </div> <div> <label for="customHeaders"> Custom Headers </label> <input id="customHeaders" type="checkbox" (click)="customHeaders($event, tabCss)"> </div> <div> <label for="tabsOnLeft"> Tabs on the Left </label> <input id="tabsOnLeft" type="checkbox" (click)="tabsOnLeft($event, tabCss)"> </div>
TS
export class AppCmp { isAnimated = true; tabAligns = 'Left,Center,Right'.split(','); constructor() { } customHeaders(e, tabCss: WjTabPanel) { wjcCore.toggleClass(tabCss.hostElement, 'custom-headers', e.target.checked); } tabsOnLeft(e, tabCss: WjTabPanel) { wjcCore.toggleClass(tabCss.hostElement, 'tabs-on-left', e.target.checked); } tabAlignChanged(cmbTabAlign: WjComboBox, tabCss: WjTabPanel) { (tabCss.hostElement.querySelector('.wj-tabheaders') as HTMLElement).style.textAlign = cmbTabAlign.text; } }
CSS
/* custom-headers */ .wj-tabpanel.custom-headers .wj-tabpanes { border-top: none; } .wj-tabpanel.custom-headers .wj-tabheaders { background: black; color: white; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader.wj-state-active { background: white; color: black; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader:not(.wj-state-active) { font-weight: normal; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader.wj-state-active:after { /* hide underline */ display: none; } /* tabs on the left*/ .wj-tabpanel.tabs-on-left > div { display: flex; align-items: center; } .wj-tabpanel.tabs-on-left .wj-tabheaders { display: flex; flex-direction: column; min-width: 8em; border-right: 1px solid #ddd; } .wj-tabpanel.tabs-on-left .wj-tabpanes { display: flex; flex-grow: 1; border-top: none; overflow-x: hidden; }

#### Result (live):

Africa

- Algeria
- Angola
- Benin
- Botswana

America

- Canada
- Chile
- Mexico
- United States

Asia

- China
- Korea
- India
- Japan

Europe

- Austria
- England
- France
- Germany
- Netherlands
- Switzerland

Oceania

- Australia
- Fiji
- New Zealand
- Samoa

Tab Alignment
isAnimated
Custom Headers
Tabs on the Left

## Disabled and Invisible Tabs

You can disable or hide individual tabs using the Tab's isDisabled and isVisible properties.

HTML
<wj-tab-panel #tabDisableHide> <wj-tab> <a>Africa</a> <div> <ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> <li>Botswana</li> </ul> </div> </wj-tab> <wj-tab> <a> America </a> <div> <ul> <li>Canada</li> <li>Chile</li> <li>Mexico</li> <li>United States</li> </ul> </div> </wj-tab> <wj-tab> <a>Asia</a> <div> <ul> <li>China</li> <li>Korea</li> <li>India</li> <li>Japan</li> </ul> </div> </wj-tab> <wj-tab [isDisabled]="isDisabled"> <a>Europe</a> <div> <ul> <li>Austria</li> <li>England</li> <li>France</li> <li>Germany</li> <li>Netherlands</li> <li>Switzerland</li> </ul> </div> </wj-tab> <wj-tab [isVisible]="isVisible"> <a>Oceania</a> <div> <ul> <li>Australia</li> <li>Fiji</li> <li>New Zealand</li> <li>Samoa</li> </ul> </div> </wj-tab> </wj-tab-panel> <div> <label for="disableEurope"> Disable Europe </label> <input id="disableEurope" type="checkbox" [(ngModel)]="isDisabled"> </div> <div> <label for="showOceania"> Show Oceania </label> <input id="showOceania" type="checkbox" [(ngModel)]="isVisible"> </div>
TS
export class AppCmp { isDisabled = true; isVisible = true constructor() { } }

#### Result (live):

Africa

- Algeria
- Angola
- Benin
- Botswana

America

- Canada
- Chile
- Mexico
- United States

Asia

- China
- Korea
- India
- Japan

Europe

- Austria
- England
- France
- Germany
- Netherlands
- Switzerland

Oceania

- Australia
- Fiji
- New Zealand
- Samoa

Disable Europe
Show Oceania

## Detached Panels

The TabPanel has a built-in panel that shows the content of the selected tab. In some cases, you may want to display the content in a different element. To do that, simply hide the built-in content element and use the selectedIndexChanged event to update the content.

HTML
<wj-tab-panel #dPanel (selectedIndexChanged)="selectTab(dPanel)"> <wj-tab> <a>Africa</a> <div> </div> </wj-tab> <wj-tab> <a>America</a> <div> </div> </wj-tab> <wj-tab> <a>Asia</a> <div> </div> </wj-tab> <wj-tab> <a>Europe</a> <div> </div> </wj-tab> <wj-tab> <a>Oceania</a> <div> </div> </wj-tab> </wj-tab-panel> <p></p> <div class="panel panel-success"> <!-- separate div to show the content --> <div class="panel-heading"> <h3 id="detachedContent" class="panel-title" [innerHtml]="selectedTabContent"></h3> </div> </div>
TS
export class AppCmp { selectedTabContent: string; constructor() { } selectTab(s: WjTabPanel) { this.selectedTabContent = 'Content for tab <b>' + s.selectedTab.header.textContent + '</b>...'; } }

#### Result (live):

Africa
America
Asia
Europe
Oceania

###

## Accessibility

The TabPanel implements WAI-ARIA accessibility guidelines. All tab elements have the proper role attributes as well as all applicable ARIA attributes.

The example below assigns unique IDs to the tab headers and panes, which the TabPanel automatically uses to generate "aria-controls" and "aria-labelledby" attributes.

The example also sets the selectedIndex property of the TabPanel to make the "America" tab initially selected. Without that, the first tab would have been selected by default.

Finally, the example shows the effect of the autoSwitch property, which affects how the control handles the tab and cursor keys. For a detailed discussion of this topic, please see the W3C ARIA practices and SimplyAccessible article.

HTML
<wj-tab-panel [autoSwitch]="autoSwitch" [selectedIndex]="1"> <wj-tab> <a id="hdr-africa">Africa</a> <div id="pane-africa"> <ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> <li>Botswana</li> </ul> </div> </wj-tab> <wj-tab> <a id="hdr-america"> America </a> <div id="pane-america"> <ul> <li>Canada</li> <li>Chile</li> <li>Mexico</li> <li>United States</li> </ul> </div> </wj-tab> <wj-tab> <a id="hdr-asia">Asia</a> <div id="pane-asia"> <ul> <li>China</li> <li>Korea</li> <li>India</li> <li>Japan</li> </ul> </div> </wj-tab> <wj-tab> <a id="hdr-europe">Europe</a> <div id="pane-europe"> <ul> <li>Austria</li> <li>England</li> <li>France</li> <li>Germany</li> <li>Netherlands</li> <li>Switzerland</li> </ul> </div> </wj-tab> <wj-tab> <a id="hdr-oceania">Oceania</a> <div id="pane-oceania"> <ul> <li>Australia</li> <li>Fiji</li> <li>New Zealand</li> <li>Samoa</li> </ul> </div> </wj-tab> </wj-tab-panel> <div> <label for="autoSwitch"> autoSwitch </label> <input id="autoSwitch" type="checkbox" [(ngModel)]="autoSwitch"> </div>
TS
export class AppCmp { autoSwitch = true; constructor() { } }

#### Result (live):

Africa

- Algeria
- Angola
- Benin
- Botswana

America

- Canada
- Chile
- Mexico
- United States

Asia

- China
- Korea
- India
- Japan

Europe

- Austria
- England
- France
- Germany
- Netherlands
- Switzerland

Oceania

- Australia
- Fiji
- New Zealand
- Samoa

autoSwitch

## Right to Left (RTL)

Some languages render content from the right to the left of the page (Arabic and Hebrew are typical examples) . HTML accommodates this with the 'dir' attribute. Setting 'dir' to 'rtl' on any element causes the element's content to flow from right to left.

The TabPanel supports this automatically. If the wj-tab-panel element has the 'dir' attribute set to 'rtl', the panel will render with tabs aligned from right to left. You don't have to set any properties on the control.

Note that the 'dir' attribute value is inherited, so if you set it on the body tag for example, the entire page will be rendered from right to left, including the TabPanel.

Note also that CSS has a 'direction' attribute that performs the same function as the 'dir' element attribute. The 'dir' attribute is generally considered more appropriate for several reasons, including the fact that it can be used in CSS rules.

HTML
<wj-tab-panel dir="rtl"> <wj-tab> <a>Africa</a> <div> <ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> <li>Botswana</li> </ul> </div> </wj-tab> <wj-tab> <a> America </a> <div> <ul> <li>Canada</li> <li>Chile</li> <li>Mexico</li> <li>United States</li> </ul> </div> </wj-tab> <wj-tab> <a>Asia</a> <div> <ul> <li>China</li> <li>Korea</li> <li>India</li> <li>Japan</li> </ul> </div> </wj-tab> <wj-tab> <a>Europe</a> <div> <ul> <li>Austria</li> <li>England</li> <li>France</li> <li>Germany</li> <li>Netherlands</li> <li>Switzerland</li> </ul> </div> </wj-tab> <wj-tab> <a>Oceania</a> <div> <ul> <li>Australia</li> <li>Fiji</li> <li>New Zealand</li> <li>Samoa</li> </ul> </div> </wj-tab> </wj-tab-panel>

#### Result (live):

Africa

- Algeria
- Angola
- Benin
- Botswana

America

- Canada
- Chile
- Mexico
- United States

Asia

- China
- Korea
- India
- Japan

Europe

- Austria
- England
- France
- Germany
- Netherlands
- Switzerland

Oceania

- Australia
- Fiji
- New Zealand
- Samoa