Angular Tabs Component

Tabs

The CoreUI Angular Tabs component offers a flexible and accessible way to create tabbed navigation in your application. It supports various styles and configurations to meet different design requirements.

Available in Other JavaScript Frameworks

CoreUI Angular Tabs Component is also available for React and Vue. Explore framework-specific implementations below:

Added in v5.2.0

Examples

The basic Angular tabs example uses the variant="tabs" prop to generate a tabbed interface.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';
import { cilHome } from '@coreui/icons';
import { IconDirective } from '@coreui/icons-angular';

@Component({
  selector: 'docs-tabs',
  templateUrl: './tabs.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module, IconDirective, IconDirective]
})
export class TabsComponent {
  cilHome = cilHome;

  handleChange($event: string | number | undefined) {
    console.log('handleChange', $event);
  }
}
<c-tabs [activeItemKey]="'profile'" (activeItemKeyChange)="handleChange($event)">
  <c-tabs-list variant="tabs">
    <button cTab itemKey="home"> <svg [cIcon]="cilHome"></svg> Home</button>
    <button cTab itemKey="profile">Profile</button>
    <button cTab itemKey="contact">Contact</button>
    <button cTab itemKey="disabled" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" itemKey="home">
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" itemKey="profile">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" itemKey="contact">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" itemKey="disabled">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Available styles

Change the style of tabs component with modifiers and utilities. Mix and match as needed, or build your own.

Unstyled

If you don’t provide the variant prop, the component will default to a basic style.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-unstyled',
  templateUrl: './tabs-unstyled.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsUnstyledComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list>
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Pills

Take that same code, but use variant="pills" instead:

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-pills',
  templateUrl: './tabs-pills.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsPillsComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list variant="pills">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Underline

With the same code, use variant="underline":

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-underline',
  templateUrl: './tabs-underline.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsUnderlineComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list variant="underline">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Underline border

Use the same code again, with variant="underline-border":

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-underline-border',
  templateUrl: './tabs-underline-border.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsUnderlineBorderComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list variant="underline-border">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Enclosed

Added in v5.7.25

Use variant="enclosed" to give the tabs a subtle border and rounded styling.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-enclosed',
  templateUrl: './tabs-enclosed.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsEnclosedComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list variant="enclosed">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Enclosed pills

Added in v5.7.25

Use variant="enclosed-pills" for a pill-style appearance of each tab, with pill-shaped borders and smoother outlines.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-enclosed-pills',
  templateUrl: './tabs-enclosed-pills.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsEnclosedPillsComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list variant="enclosed-pills">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Tabs layout

Fill

Force your tabs content to extend the full available width one of modifier classes. To proportionately fill all available space use layout="fill". With all horizontal space occupied, not every tab item has the same width.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-fill',
  templateUrl: './tabs-fill.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsFillComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list layout="fill" variant="tabs">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile tab with longer content</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Justify

For equal-width elements, use layout="justified". All horizontal space is occupied by tabs, but unlike the layout="fill" above, every tab item has the same width.

import { Component } from '@angular/core';
import { Tabs2Module } from '@coreui/angular';

@Component({
  selector: 'docs-tabs-justify',
  templateUrl: './tabs-justify.component.html',
  styleUrls: ['./tabs.component.scss'],
  imports: [Tabs2Module]
})
export class TabsJustifyComponent {}
<c-tabs [activeItemKey]="1" >
  <c-tabs-list layout="justified" variant="tabs">
    <button cTab [itemKey]="0">Home</button>
    <button cTab [itemKey]="1">Profile details</button>
    <button cTab [itemKey]="2">Contact</button>
    <button cTab [itemKey]="3" disabled>Disabled</button>
  </c-tabs-list>
  <c-tabs-content>
    <c-tab-panel class="p-3" [itemKey]="0" >
      <strong>Home</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="1">
      <strong>Profile</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="2">
      <strong>Contact</strong> tab content
    </c-tab-panel>
    <c-tab-panel class="p-3" [itemKey]="3">
      <strong>Disabled</strong> tab content
    </c-tab-panel>
  </c-tabs-content>
</c-tabs>
:host {
  height: 6rem;
  display: block;
}

Accessibility

Dynamic tabbed interfaces, as described in the WAI ARIA Authoring Practices, require role="tablist", role="tab", role="tabpanel", and additional aria- attributes convey their structure, functionality and current state to users of assistive technologies (such as screen readers).

WAI-ARIA Roles

  • The element that serves as the container for the set of tabs has the role tablist.
  • Each element that serves as a tab has the role tab and is contained within the element with the role tablist.
  • Each element that contains the content panel for a tab has the role tabpanel.
  • If the tab list has a visible label, the element with the role tablist has aria-labelledby set to a value that refers to the labeling element. Otherwise, the tablist element has a label provided by aria-label.
  • Each element with the role tab has the property aria-controls referring to its associated tabpanel element.
  • The active tab element has the state aria-selected set to true, and all other tab elements have it set to false.
  • Each element with the role tabpanel has the property aria-labelledby referring to its associated tab element.

CoreUI Angular Tabs component automatically manages all role="..." and aria- attributes for accessibility. It also handles the selected state by adding aria-selected="true" to the active tab. A tab and a tab panel with the same itemKey refer to each other: the tab’s aria-controls takes the panel’s id, and the panel’s aria-labelledby takes the tab’s id, including an id you set yourself. Without a matching panel or tab they use the default ids {c-tabs id}-panel-{itemKey} and {c-tabs id}-tab-{itemKey}. An aria-controls or aria-labelledby you set yourself takes precedence.

Keyboard Interaction

When focus enters the tabs list:

  • Tab: It places focus on the active tab element, or on the first enabled tab when no tab is active. When no tab is active and every tab is disabled, the tab list is skipped.

When focus is on a tab element:

  • Tab: Moves focus to the next element in the tab sequence, typically the tabpanel unless the first focusable element inside the tabpanel is found earlier.
  • Left Arrow: Moves focus to the previous enabled tab and activates it. If on the first enabled tab, it wraps around to the last enabled tab.
  • Right Arrow: Moves focus to the next enabled tab and activates it. If on the last enabled tab, it wraps around to the first enabled tab.
  • Home: Moves focus to the first enabled tab and activates it.
  • End: Moves focus to the last enabled tab and activates it.
  • Enter or Space: Activates the focused tab.

Focus alone does not activate a tab. The arrow keys skip disabled tabs and are mirrored in a right-to-left layout. A disabled active tab keeps aria-selected="true" and stays in the tab sequence with aria-disabled="true" instead of disabled, so the tab list keeps its place.

Customizing

CSS variables

CoreUI Angular tabs use local CSS variables on .nav, .nav-tabs, .nav-pills, .nav-underline and .nav-underline-border for enhanced real-time customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too.

On the .nav base class:

--cui-nav-link-padding-x: #{$nav-link-padding-x};
--cui-nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --cui-nav-link-font-size);
--cui-nav-link-font-weight: #{$nav-link-font-weight};
--cui-nav-link-color: #{$nav-link-color};
--cui-nav-link-hover-color: #{$nav-link-hover-color};
--cui-nav-link-disabled-color: #{$nav-link-disabled-color};

On the .nav-tabs modifier class:

--cui-nav-tabs-border-width: #{$nav-tabs-border-width};
--cui-nav-tabs-border-color: #{$nav-tabs-border-color};
--cui-nav-tabs-border-radius: #{$nav-tabs-border-radius};
--cui-nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color};
--cui-nav-tabs-link-active-color: #{$nav-tabs-link-active-color};
--cui-nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg};
--cui-nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color};

On the .nav-pills modifier class:

--cui-nav-pills-border-radius: #{$nav-pills-border-radius};
--cui-nav-pills-link-active-color: #{$nav-pills-link-active-color};
--cui-nav-pills-link-active-bg: #{$nav-pills-link-active-bg};

On the .nav-underline-border modifier class:

--cui-nav-underline-border-gap: #{$nav-underline-border-gap};
--cui-nav-underline-border-border-color: #{$nav-underline-border-border-color};
--cui-nav-underline-border-border-width: #{$nav-underline-border-border-width};
--cui-nav-underline-border-link-padding-x: #{$nav-underline-border-link-padding-x};
--cui-nav-underline-border-link-padding-y: #{$nav-underline-border-link-padding-y};
--cui-nav-underline-border-link-color: #{$nav-underline-border-link-color};
--cui-nav-underline-border-link-active-color: #{$nav-underline-border-link-active-color};
--cui-nav-underline-border-link-disabled-color: #{$nav-underline-border-link-disabled-color};

How to use CSS variables

const vars = {
'--my-css-var': 10,
'--my-another-css-var': "red"
}
<div [ngStyle]="vars"></div>

SASS variables

$nav-link-padding-y:                .5rem !default;
$nav-link-padding-x:                1rem !default;
$nav-link-font-size:                null !default;
$nav-link-font-weight:              null !default;
$nav-link-color:                    var(--cui-link-color) !default;
$nav-link-hover-color:              var(--cui-link-hover-color) !default;
$nav-link-transition:               color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;
$nav-link-disabled-color:           var(--cui-secondary-color) !default;
$nav-link-focus-box-shadow:         $focus-ring-box-shadow !default;

$nav-tabs-border-color:             var(--cui-border-color) !default;
$nav-tabs-border-width:             var(--cui-border-width) !default;
$nav-tabs-border-radius:            var(--cui-border-radius) !default;
$nav-tabs-link-hover-border-color:  var(--cui-secondary-bg) var(--cui-secondary-bg) $nav-tabs-border-color !default;
$nav-tabs-link-active-color:        var(--cui-emphasis-color) !default;
$nav-tabs-link-active-bg:           var(--cui-body-bg) !default;
$nav-tabs-link-active-border-color: var(--cui-border-color) var(--cui-border-color) $nav-tabs-link-active-bg !default;

$nav-pills-border-radius:           var(--cui-border-radius) !default;
$nav-pills-link-active-color:       $component-active-color !default;
$nav-pills-link-active-bg:          $component-active-bg !default;

$nav-underline-gap:                 1rem !default;
$nav-underline-border-width:        .125rem !default;
$nav-underline-link-active-color:   var(--cui-emphasis-color) !default;

$nav-underline-border-gap:                  .5rem !default;
$nav-underline-border-border-color:         var(--cui-border-color) !default;
$nav-underline-border-border-width:         .125rem !default;
$nav-underline-border-link-padding-y:       .5rem !default;
$nav-underline-border-link-padding-x:       .5rem !default;
$nav-underline-border-link-color:           var(--cui-secondary-color) !default;
$nav-underline-border-link-active-color:    var(--cui-primary) !default;
$nav-underline-border-link-disabled-color:  var(--cui-tertiary-color) !default;

API reference

Tabs2Module

  • with standalone components:
import { Tabs2Module } from '@coreui/angular';

@Component({
    selector: 'your-component',
    standalone: true,
    imports: [Tabs2Module]
})
export class YourComponent() { }
  • with NgModules:
import { Tabs2Module } from '@coreui/angular';

@NgModule({
    imports: [Tabs2Module]
})
export class YourModule() { }

c-tabs

component exportAs: cTabs

jsx
import { TabsComponent } from '@coreui/angular'

Props

PropertyDefaultType
activeItemKey-string, number

The active item key.

idtabs-{n}string, null

HTML id attribute.

Events

Event name
activeItemKeyChange

Emitted when activeItemKey changes.

  • $event string | number | undefined

c-tabs-list

component exportAs: cTabsList

jsx
import { TabsListComponent } from '@coreui/angular'
PropertyDefaultType
layoutundefined'fill', 'justified'

Specify a layout type for component.

role'tablist'string

Set the role to tab list.

variantundefined'enclosed', 'enclosed-pills', 'pills', 'tabs', 'underline', 'underline-border'

Set the variant to tabs, pills, underline or enclosed.

cTab

directive exportAs: cTab

jsx
import { TabDirective } from '@coreui/angular'
PropertyDefaultType
aria-controls{c-tabs id}-panel-{itemKey}string, null

aria-controls attribute. Follows the id of the c-tab-panel with the same itemKey, a custom one included.

disabledfalseboolean

Disables the tab. A disabled tab that is selected or has focus stays focusable with aria-disabled.

id{c-tabs id}-tab-{itemKey}string, null

Element id attribute

itemKey-string, number

Item key.

c-tabs-content

component exportAs: cTabsContent

  • wrapper for tab panels
jsx
import { TabsContentComponent } from '@coreui/angular'

c-tab-panel

component exportAs: cTabPanel

jsx
import { TabPanelComponent } from '@coreui/angular'

Props

PropertyDefaultType
aria-labelledby{c-tabs id}-tab-{itemKey}string, null

aria-labelledby attribute. Follows the id of the cTab with the same itemKey, a custom one included.

id{c-tabs id}-panel-{itemKey}string, null

Element id attribute

itemKey-string, number

Item key.

role'tabpanel'string

Element role.

tabindex0number

tabindex attribute.

transitiontrueboolean

Enable fade in transition.

Events

Event name
visibleChange

visible change output

  • $event VisibleChangeEvent