# TabPanel 101

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

## Getting Started

Steps for getting started with FlexGrid in AngularJS applications:

1. Add references to AngularJS, Wijmo, and Wijmo's AngularJS directives.
2. Include the Wijmo directives in the app module:
   `var app = angular.module('app', ['wj']);`
3. Add a controller to provide data and logic.
4. Add wj-tab-panel with nested wj-tab directives to the template.
5. 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
<html> <head> <!-- Third Party --> <script src="bin/Devel/external/angular.js"></script> <link rel="stylesheet" href="bin/Devel/external/bootstrap/css/bootstrap.css"/> <!-- Wijmo --> <script wj-src="wijmo" src="bin/Devel/loaders/wijmo.load.module.js"></script> <script wj-src="wijmo.nav" src="bin/Devel/loaders/wijmo.load.module.js"></script> <script wj-src="wijmo.angular" src="bin/Devel/loaders/wijmo.load.module.js"></script> <link rel="stylesheet" href="bin/Devel/sources/styles/wijmo.css" /> <!-- app scripts and styles --> <script src="scripts/app.js"></script> <script src="scripts/controllers/appCtrl.js"></script> <link href="styles/app.css" rel="stylesheet" /> </head> <body ng-app="app" ng-controller="appCtrl"> <wj-tab-panel selected-index="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> </body> </html>
JS
// declare app module var app = angular.module('app', ['wj']); // app controller provides data app.controller('appCtrl', function appCtrl($scope) { });

#### 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 items-source="data"> </wj-flex-grid> </div> </wj-tab> <wj-tab> <a>FlexChart</a> <div> <wj-flex-chart items-source="data" binding-x="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> <wj-radial-gauge style="display:block" value="75" min="0" is-read-only="false" max="100"> </wj-radial-gauge> <wj-linear-gauge style="display:block" value="75" min="0" is-read-only="false" max="100"> </wj-linear-gauge> </div> </wj-tab> </wj-tab-panel>
JS
// generate some random data function getData(count) { 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; } // expose data as a CollectionView (to get updates on changes) $scope.data = new wijmo.collections.CollectionView(getData(100));

#### 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 ng-repeat 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 selected-index="0"> <wj-tab ng-repeat="tab in tabsInfo" is-disabled="{{!tab.isEnabled}}"> <a>{{tab.header}}</a> <div> <wj-flex-grid is-read-only="true" items-source="tab.data"> </wj-flex-grid> </div> </wj-tab> </wj-tab-panel>
JS
$scope.tabsInfo = []; _initTabsInfo(); function _initTabsInfo() { let headers = 'Employees,Categories,Products,Customers'.split(','), url = 'http://services.odata.org/Northwind/Northwind.svc/'; $scope.tabsInfo = []; headers.forEach((header) => { $scope.tabsInfo.push({ header: header, data: new wijmo.odata.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 control="tabCss" class="custom-tab" is-animated="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 control="cmbTabAlign" items-source="tabAligns" selected-index-changed="tabAlignChanged(cmbTabAlign, tabCss)"> </wj-combo-box> </div> <div> <label for="isAnimated"> isAnimated </label> <input id="isAnimated" type="checkbox" checked="checked" ng-model="isAnimated"> </div> <div> <label for="customHeaders"> Custom Headers </label> <input id="customHeaders" type="checkbox" ng-click="customHeaders($event, tabCss)"> </div> <div> <label for="tabsOnLeft"> Tabs on the Left </label> <input id="tabsOnLeft" type="checkbox" ng-click="tabsOnLeft($event, tabCss)"> </div>
JS
$scope.isAnimated = true; $scope.tabAligns = 'Left,Center,Right'.split(','); $scope.customHeaders = function(e, tabCss) { wijmo.toggleClass(tabCss.hostElement, 'custom-headers', e.target.checked); } $scope.tabsOnLeft= function(e, tabCss) { wijmo.toggleClass(tabCss.hostElement, 'tabs-on-left', e.target.checked); } $scope.tabAlignChanged=function(cmbTabAlign, tabCss) { tabCss.hostElement.querySelector('.wj-tabheaders').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; }
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> <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 is-disabled="{{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 is-visible="{{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" ng-model="isDisabled"> </div> <div> <label for="showOceania"> Show Oceania </label> <input id="showOceania" type="checkbox" ng-model="isVisible"> </div>
JS
$scope.isDisabled = true; $scope.isVisible = true;

#### 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 control="dPanel" selected-index-changed="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" ng-bind-html="selectedTabContent"></h3> </div> </div>
JS
// expose the data as a CollectionView to show grouping $scope.dPanel = null; $scope.selectedTabContent=''; $scope.selectTab= function(tab) { setSelectedTabContent(); $scope.$apply(); } $scope.$watch('dPanel', function () { setSelectedTabContent(); }) function setSelectedTabContent() { if (!$scope.dPanel) { return; } $scope.selectedTabContent = $sce.trustAsHtml('Content for tab ' + $scope.dPanel.selectedTab.header.textContent + '...'); }

#### 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 auto-switch="autoSwitch" selected-index="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" ng-model="autoSwitch"> </div>
JS
$scope.autoSwitch = true;

#### 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