Overview

Displays the tab list of a tabbed interface:

KTabsList is meant to be used together with KTabsPanel, which displays tabs' content. Using these two components is recommended in situations when KTabs is not sufficient, for example, when a tab list is rendered within a different component than tab panels.

Basic usage

Tab list items are rendered as buttons. Tab panels' content is passed via KTabsPanel slots named by corresponding tabs' IDs from objects of the tabs array. The component takes care of displaying only content corresponding to the active tab.

Each tabbed interface needs to have ariaLabel or ariaLabelledBy and also an identifier, tabsID, that is unique in regard to a page where tabs are rendered. Another purpose of tabsId is to link KTabsList and KTabsPanel representing a single tabbed interface. These two components also need to share information about the currently active tab stored in activeTabId.


      <AppBar>
        <KTabsList
          v-model="activeTabId"
          tabsId="coachReportsTabs"
          ariaLabel="Coach reports"
          :tabs="tabs"
        />
      </AppBar>

      <KTabsPanel
        tabsId="coachReportsTabs"
        :activeTabId="activeTabId"
      >
        <template #tabLessons>
          Lessons tab content
        </template>
        <template #tabLearners>
          Learners tab content
        </template>
        <template #tabGroups>
          Groups tab content
        </template>
      </KTabsPanel>
    

      data() {
        return {
          activeTabId: 'tabLessons',
          tabs: [
            { id: 'tabLessons', label: 'Lessons' },
            { id: 'tabLearners', label: 'Learners' },
            { id: 'tabGroups', label: 'Groups' },
          ],
        };
      },
    

With router

When implementing tabs with the router, it's the router view rather than KTabsPanel that is responsible for displaying the active tab content.

In such a case, define to property with a router link object as its value in objects of the tabs array:


      data() {
        return {
          tabs: [
            { id: 'tabLessons', label: 'Lessons', to: { path: '/lessons' } },
            { id: 'tabLearners', label: 'Learners', to: { path: '/learners' } },
            { id: 'tabGroups', label: 'Groups', to: { path: '/groups' } },
          ],
        };
      },
    

Then, tabs will be rendered as router links and you can use the router view to display the active tab content:


      <AppBar>
        <KTabsList
          v-model="activeTabId"
          tabsId="coachReportsTabs"  
          ariaLabel="Coach reports"
          :tabs="tabs"
        />
      </AppBar>

      <KTabsPanel
        tabsId="coachReportsTabs"
        :activeTabId="activeTabId"
      >
        <router-view />
      </KTabsPanel>
    

Note that here, tabs content is not passed to KTabsPanel via named slots, for it's the router view that's responsible for rendering it.

However, it is still required to wrap the active tab content in KTabsPanel. Otherwise, even though tabs may seem to function correctly at first glance, accessibility would be broken.

Do

          <AppBar>
            <KTabsList
              v-model="activeTabId"
              tabsId="coachReportsTabs"
              ariaLabel="Coach reports"
              :tabs="tabs"
            />
          </AppBar>

          <KTabsPanel
            tabsId="coachReportsTabs"
            :activeTabId="activeTabId"
          >
            <!-- the active tab content is displayed in this router view -->
            <router-view />
          </KTabsPanel>
        

Place the router view to KTabsPanel default slot

Don't

          <AppBar>
            <KTabsList
              v-model="activeTabId"
              tabsId="coachReportsTabs"
              ariaLabel="Coach reports"
              :tabs="tabs"
            />
          </AppBar>

          <KTabsPanel
            tabsId="coachReportsTabs"
            :activeTabId="activeTabId"
          />
          <!-- the active tab content is displayed in this router view -->
          <router-view />
        

Place the router view outside of KTabsPanel or forget to use KTabsPanel altogether

More tabs on a page

When there are two or more tabbed interfaces on one page, it is important to identify each one of them with an ID unique in regard to the page. Otherwise, some a11y features may break.

This is achieved by providing a unique value to tabsId property:


      <KTabsList tabsId="firstTabs" />
      <KTabsPanel tabsId="firstTabs" />

      <KTabsList tabsId="secondTabs" />
      <KTabsPanel tabsId="secondTabs" />
    

Appearance

There are several ways to adjust tabs styling.

Using props is the most straightforward:


      <KTabsList
        v-model="activeTabId"
        tabsId="tabsProps"
        ariaLabel="Coach reports"
        :tabs="tabs"
        :color="$themeTokens.textInverted"
        :colorActive="$themeTokens.textInverted"
        :backgroundColor="$themeTokens.primary"
        :hoverBackgroundColor="$themeTokens.primaryDark"
      />
    

When that's not sufficient, appearanceOverrides and appearanceOverridesActive can be used, where the former complements or overrides styles common to all tabs and the latter contains styles specific to an active tab:


      <KTabsList
        v-model="activeTabId"
        tabsId="tabsAppearanceOverrides"
        ariaLabel="Coach reports"
        :tabs="tabs"
        :appearanceOverrides="{
          ':hover': {
            color: $themeTokens.primary
          },
          textTransform: 'none',
          margin: '0 32px'
        }"
        :appearanceOverridesActive="{
          borderBottomWidth: '6px'
        }"
      />
    

Lastly, the tab slot can be used to adjust labels, for example to add icons. It's a scoped slot that exposes tab object and isActive boolean value:


      <KTabsList
        v-model="activeTabId"
        tabsId="tabsSlot"
        ariaLabel="Coach reports"
        :tabs="tabs"
      >
        <template #tab="{ tab, isActive }">
          <KLabeledIcon
            :icon="icons[tab.id]"
            :label="tab.label"
            :color="isActive ? $themeTokens.primary : $themeTokens.annotation"
          />
        </template>
      </KTabsList>
    

      icons: {
        tabLessons: 'lesson',
        tabLearners: 'person',
        tabGroups: 'people',
      },
    

Related

  • Tabs page has an overview and usage guidance for all tab-related components
  • KTabsPanel is a component to be used together with KTabsList
  • KTabs is an alternative way to implement tabs

Props

Name Description Type Default Required
tabs
An array of tab objects { id, label, to } where id and label properties are required and to is optional. When to is provided, tabs render as router links. Otherwise, they render as buttons.
array true
ariaLabel
A label that describes the purpose of the set of tabs. Providing either ariaLabel or ariaLabelledBy is required.
string ''
ariaLabelledBy
ID reference to a DOM element which provides a label that describes the purpose of the set of tabs. Providing either ariaLabel or ariaLabelledBy is required.
string ''
color
Tabs text color. Defaults to $themeTokens.annotation.
string null
colorActive
Text color of an active tab. Defaults to $themeTokens.primary.
string null
backgroundColor
Tabs background color. Defaults to $themeTokens.surface.
string null
hoverBackgroundColor
Tabs hover background color. Defaults to $themeBrand.primary.v_100.
string null
appearanceOverrides
Tabs styles that complement or override default styles or styles defined via props (will be sent to $computedClass, which means that styles that are accepted by $computedClass, e.g. pseudo-classes, are supported)
object null
appearanceOverridesActive
An active tab styles that complement or override default styles or styles defined via props (will be sent to $computedClass, which means that styles that are accepted by $computedClass, e.g. pseudo-classes, are supported)
object null
enablePrint
Tab list items are hidden when printing by default. enablePrint set to true makes them visible in print mode.
boolean false
tabsId
An ID of a tabbed interface that this component is part of. Needs to be be unique in regards to all tabbed interfaces rendered on one page.
string true
v-model
An ID of an active tab.
string true

Events

Name Description
activate
Emitted when a tab is activated. Its payload is the active tab ID.
click
Emitted when a tab is clicked. Its payload is the active tab ID. When compared to the activate event, click is emitted only when a user is interacting with tabs, whereas activate can be emitted programatically in addition to user interaction.

Slots

Name Description
tab
Optional slot for tab labels. Exposes tab object and isActive boolean.

Methods

Name Description
focusActiveTab
Puts focus on the active tab