DevExtreme v24.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Angular Tabs - Overview

The Tabs component allows you to create a tabbed UI to navigate between pages or views. You can create tab items in the items array, or populate tab items from a dataSource.

DevExtreme Accessibility Compliance
DevExtreme component libraries meet a variety of WCAG and Section 508 compliance standards. To assess this demo’s accessibility level, click the Run AXE® Validation button to launch the AXE® web accessibility evaluation tool.
All trademarks or registered trademarks are property of their respective owners. AXE® Terms of Use
The overall accessibility level of your application depends on the Tabs features used.
Backend API
<div class="tabs-demo"> <div class="widget-container"> <div [ngClass]="widgetWrapperClasses"> <dx-tabs #withText [width]="width" [selectedIndex]="0" [rtlEnabled]="rtlEnabled" [scrollByContent]="scrollByContent" [showNavButtons]="showNavButtons" [dataSource]="tabsWithText" [orientation]="orientation" [stylingMode]="stylingMode" [iconPosition]="iconPosition" ></dx-tabs> <dx-tabs #withIconAndText [width]="width" [selectedIndex]="0" [rtlEnabled]="rtlEnabled" [scrollByContent]="scrollByContent" [showNavButtons]="showNavButtons" [dataSource]="tabsWithIconAndText" [orientation]="orientation" [stylingMode]="stylingMode" [iconPosition]="iconPosition" ></dx-tabs> <dx-tabs #withIcon [width]="width" [selectedIndex]="0" [rtlEnabled]="rtlEnabled" [scrollByContent]="scrollByContent" [showNavButtons]="showNavButtons" [dataSource]="tabsWithIcon" [orientation]="orientation" [stylingMode]="stylingMode" [iconPosition]="iconPosition" ></dx-tabs> </div> </div> <div class="options"> <div class="caption">Options</div> <div class="option"> <span>Orientation</span> <dx-select-box [inputAttr]="{ 'aria-label': 'Orientation' }" [items]="orientations" [(value)]="orientation" (onValueChanged)="onOrientationChanged($event)" ></dx-select-box> </div> <div class="option"> <span>Styling mode</span> <dx-select-box [inputAttr]="{ 'aria-label': 'Styling Mode' }" [items]="stylingModes" [(value)]="stylingMode" ></dx-select-box> </div> <div class="option"> <span>Icon position</span> <dx-select-box [inputAttr]="{ 'aria-label': 'Icon Position' }" [items]="iconPositions" [(value)]="iconPosition" ></dx-select-box> </div> <div class="option"> <dx-check-box id="show-navigation-buttons" text="Show navigation buttons" [(value)]="showNavButtons" (onValueChanged)="toggleStrictWidthClass()" ></dx-check-box> </div> <div class="option"> <dx-check-box text="Scroll content" [(value)]="scrollByContent" (onValueChanged)="toggleStrictWidthClass()" ></dx-check-box> </div> <div class="option"> <dx-check-box text="Full width" [value]="false" (onValueChanged)="onFullWidthChanged($event)" ></dx-check-box> </div> <div class="option"> <dx-check-box text="Right-to-left mode" [(value)]="rtlEnabled" ></dx-check-box> </div> </div> </div>
import { NgModule, Component, enableProdMode, ViewChild, } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { DxSelectBoxModule, DxSelectBoxTypes } from 'devextreme-angular/ui/select-box'; import { DxCheckBoxModule, DxCheckBoxTypes } from 'devextreme-angular/ui/check-box'; import { DxTabsModule, DxTabsComponent, DxTabsTypes } from 'devextreme-angular/ui/tabs'; import { Tab, Service } from './app.service'; if (!/localhost/.test(document.location.host)) { enableProdMode(); } @Component({ selector: 'demo-app', templateUrl: `app/app.component.html`, styleUrls: [`app/app.component.css`], providers: [Service], }) export class AppComponent { @ViewChild('withText') withText: DxTabsComponent; @ViewChild('withIconAndText') withIconAndText: DxTabsComponent; @ViewChild('withIcon') withIcon: DxTabsComponent; tabsWithText: Tab[]; tabsWithIconAndText: Tab[]; tabsWithIcon: Tab[]; showNavButtons = false; scrollByContent = false; rtlEnabled = false; orientations: DxTabsTypes.Orientation[] = ['horizontal', 'vertical']; stylingModes: DxTabsTypes.TabsStyle[] = ['primary', 'secondary']; iconPositions: DxTabsTypes.TabsIconPosition[] = ['top', 'start', 'end', 'bottom']; width = 'auto'; orientation = this.orientations[0]; stylingMode = this.stylingModes[1]; iconPosition = this.iconPositions[0]; widgetWrapperClasses = { 'widget-wrapper': true, 'widget-wrapper-horizontal': true, 'widget-wrapper-vertical': false, 'strict-width': false, }; constructor(service: Service) { this.tabsWithText = service.getTabsWithText(); this.tabsWithIconAndText = service.getTabsWithIconAndText(); this.tabsWithIcon = service.getTabsWithIcon(); } onOrientationChanged(e: DxSelectBoxTypes.ValueChangedEvent) { if (e.value === 'vertical') { this.widgetWrapperClasses['widget-wrapper-vertical'] = true; this.widgetWrapperClasses['widget-wrapper-horizontal'] = false; } else { this.widgetWrapperClasses['widget-wrapper-horizontal'] = true; this.widgetWrapperClasses['widget-wrapper-vertical'] = false; } } toggleStrictWidthClass() { this.widgetWrapperClasses['strict-width'] = this.scrollByContent || this.showNavButtons; } onFullWidthChanged(e: DxCheckBoxTypes.ValueChangedEvent) { this.width = e.value ? '100%' : 'auto'; } } @NgModule({ imports: [ BrowserModule, DxTabsModule, DxCheckBoxModule, DxSelectBoxModule, ], declarations: [AppComponent], bootstrap: [AppComponent], }) export class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule);
::ng-deep .tabs-demo { display: flex; } ::ng-deep .strict-width { max-width: 340px; } ::ng-deep .dx-theme-generic .strict-width { max-width: 250px; } ::ng-deep .widget-container { display: flex; align-items: center; justify-content: center; flex-grow: 1; width: 100%; min-width: 200px; padding: 16px 32px; overflow: clip; } ::ng-deep .widget-wrapper { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 80px; width: 100%; } ::ng-deep .widget-wrapper-vertical { width: 100%; flex-direction: row; align-items: center; } .options { display: flex; flex-direction: column; flex-shrink: 0; padding: 20px; background-color: rgba(191, 191, 191, 0.15); } .caption { font-weight: 500; font-size: 18px; } ::ng-deep #show-navigation-buttons { margin-top: 22px; } .option { margin-top: 20px; } ::ng-deep .dx-tabs { max-width: 100%; } ::ng-deep .dx-tabs-vertical { height: 216px; } ::ng-deep .dx-viewport:not(.dx-theme-generic) .dx-tabs-horizontal { border-block-end: 1px solid rgb(225, 225, 225, 0.4); } ::ng-deep .dx-viewport:not(.dx-theme-generic) .dx-tabs-vertical { height: 232px; border-inline-end: 1px solid rgb(225, 225, 225, 0.4); }
import { Injectable } from '@angular/core'; export class Tab { id: number; text?: string; icon?: string; } const tabsWithText: Tab[] = [ { id: 0, text: 'User', }, { id: 1, text: 'Analytics', }, { id: 2, text: 'Clients', }, { id: 3, text: 'Orders', }, { id: 4, text: 'Favorites', }, { id: 5, text: 'Search', }, ]; const tabsWithIcon: Tab[] = [ { id: 0, icon: 'user', }, { id: 1, icon: 'chart', }, { id: 2, icon: 'accountbox', }, { id: 3, icon: 'ordersbox', }, { id: 4, icon: 'bookmark', }, { id: 5, icon: 'search', }, ]; const tabsWithIconAndText: Tab[] = [ { id: 0, text: 'User', icon: 'user', }, { id: 1, text: 'Analytics', icon: 'chart', }, { id: 2, text: 'Clients', icon: 'accountbox', }, { id: 3, text: 'Orders', icon: 'ordersbox', }, { id: 4, text: 'Favorites', icon: 'bookmark', }, { id: 5, text: 'Search', icon: 'search', }, ]; @Injectable() export class Service { getTabsWithText(): Tab[] { return tabsWithText; } getTabsWithIconAndText(): Tab[] { return tabsWithIconAndText; } getTabsWithIcon(): Tab[] { return tabsWithIcon; } }
// In real applications, you should not transpile code in the browser. // You can see how to create your own application with Angular and DevExtreme here: // https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/ const componentNames = [ 'accordion', 'action-sheet', 'autocomplete', 'bar-gauge', 'box', 'bullet', 'button-group', 'button', 'calendar', 'chart', 'check-box', 'circular-gauge', 'color-box', 'context-menu', 'data-grid', 'date-box', 'date-range-box', 'defer-rendering', 'diagram', 'draggable', 'drawer', 'drop-down-box', 'drop-down-button', 'file-manager', 'file-uploader', 'filter-builder', 'form', 'funnel', 'gallery', 'gantt', 'html-editor', 'linear-gauge', 'list', 'load-indicator', 'load-panel', 'lookup', 'map', 'menu', 'multi-view', 'nested', 'number-box', 'pie-chart', 'pivot-grid-field-chooser', 'pivot-grid', 'polar-chart', 'popover', 'popup', 'progress-bar', 'radio-group', 'range-selector', 'range-slider', 'recurrence-editor', 'resizable', 'responsive-box', 'sankey', 'scheduler', 'scroll-view', 'select-box', 'slider', 'sortable', 'sparkline', 'speed-dial-action', 'splitter', 'switch', 'tab-panel', 'tabs', 'tag-box', 'text-area', 'text-box', 'tile-view', 'toast', 'toolbar', 'tooltip', 'tree-list', 'tree-map', 'tree-view', 'validation-group', 'validation-summary', 'validator', 'vector-map', ]; window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, }, meta: { 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, '@angular/platform-browser-dynamic': { 'esModule': true, }, '@angular/platform-browser': { 'esModule': true, }, '@angular/core': { 'esModule': true, }, '@angular/common': { 'esModule': true, }, '@angular/common/http': { 'esModule': true, }, '@angular/compiler': { 'esModule': true, }, '@angular/animations': { 'esModule': true, }, '@angular/forms': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', }, map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', /* @angular */ '@angular/compiler': 'bundles:@angular/compiler.umd.js', '@angular/platform-browser-dynamic': 'bundles:@angular/platform-browser-dynamic.umd.js', '@angular/core': 'bundles:@angular/core.umd.js', '@angular/core/primitives/signals': 'bundles:@angular/core.primitives.signals.umd.js', '@angular/common': 'bundles:@angular/common.umd.js', '@angular/common/http': 'bundles:@angular/common-http.umd.js', '@angular/platform-browser': 'bundles:@angular/platform-browser.umd.js', '@angular/platform-browser/animations': 'bundles:@angular/platform-browser.umd.js', '@angular/forms': 'bundles:@angular/forms.umd.js', /* devextreme */ 'devextreme': 'npm:devextreme@24.1.6/cjs', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'devextreme/bundles/dx.all': 'npm:devextreme@24.1.6/bundles/dx.all.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.11', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56', /* devextreme-angular umd maps */ 'devextreme-angular': 'bundles:devextreme-angular/devextreme-angular.umd.js', 'devextreme-angular/core': 'bundles:devextreme-angular/devextreme-angular-core.umd.js', 'devextreme-angular/http': 'bundles:devextreme-angular/devextreme-angular-http.umd.js', ...componentNames.reduce((acc, name) => { acc[`devextreme-angular/ui/${name}`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}.umd.js`; return acc; }, {}), 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'tslib': 'npm:tslib@2.6.1/tslib.js', 'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js', 'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'app': { main: './app.component.ts', defaultExtension: 'ts', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, 'rxjs': { defaultExtension: 'js', }, 'rxjs/operators': { defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', 'npm:rxjs@7.5.3/package.json', 'npm:rxjs@7.5.3/operators/package.json', 'npm:devexpress-diagram@2.2.11/package.json', 'npm:devexpress-gantt@4.1.56/package.json', ], }; System.config(window.config); // System.import('@angular/compiler').catch(console.error.bind(console));
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.6/css/dx.light.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/zone.js@0.13.3/bundles/zone.umd.min.js"></script> <script src="https://unpkg.com/reflect-metadata@0.1.13/Reflect.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script src="config.js"></script> <script> System.import("app").catch(console.error.bind(console)); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <demo-app>Loading...</demo-app> </div> </body> </html>

Customize Tab Contents and Appearance

You can initialize a tab’s contents (text, icons and badges) with values from underlying data objects. This example demonstrates this technique.

Use the drop-down editors on the right to change the component's orientation, styling mode, and icon position.

You can also specify an item template (itemTemplate) to customize tabs.

Configure Overflow Behavior

The Tabs component stretches to fit its container if you do not specify the component's width. When the total tab width exceeds the component’s width, navigation buttons appear. A user can click these buttons to scroll through the tabs. Use the showNavButtons and scrollByContent properties to control this behavior.