React Tabs Components

Tabs

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

Example#

The basic React tabs example uses the variant="tabs" props to generate a tabbed interface.

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey="profile">
<CTabList variant="tabs">
<CTab itemKey="home">Home</CTab>
<CTab itemKey="profile">Profile</CTab>
<CTab itemKey="contact">Contact</CTab>
<CTab disabled itemKey="disabled">Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="p-3" itemKey="home">
Home tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="profile">
Profile tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="contact">
Contact tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="disabled">
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Available styles#

Change the style of <CTabs>'s 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.

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey="profile">
<CTabList>
<CTab itemKey="home">Home</CTab>
<CTab itemKey="profile">Profile</CTab>
<CTab itemKey="contact">Contact</CTab>
<CTab disabled itemKey="disabled">Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="p-3" itemKey="home">
Home tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="profile">
Profile tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="contact">
Contact tab content
</CTabPanel>
<CTabPanel className="p-3" itemKey="disabled">
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Pills#

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

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey={2}>
<CTabList variant="pills">
<CTab aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab aria-controls="profile-tab-pane" itemKey={2}>Profile</CTab>
<CTab aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="p-3" aria-labelledby="home-tab-pane" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel className="p-3" aria-labelledby="profile-tab-pane" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel className="p-3" aria-labelledby="contact-tab-pane" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel className="p-3" aria-labelledby="disabled-tab-pane" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Underline#

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

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey={2}>
<CTabList variant="underline">
<CTab aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab aria-controls="profile-tab-pane" itemKey={2}>Profile</CTab>
<CTab aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="py-3" aria-labelledby="home-tab-pane" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="profile-tab-pane" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="contact-tab-pane" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="disabled-tab-pane" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Underline border#

Take that same code, but use variant="underline-border" instead:

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey={2}>
<CTabList variant="underline-border">
<CTab aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab aria-controls="profile-tab-pane" itemKey={2}>Profile</CTab>
<CTab aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="py-3" aria-labelledby="home-tab-pane" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="profile-tab-pane" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="contact-tab-pane" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="disabled-tab-pane" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Fill and justify#

Force your <CTabs>'s contents to extend the full available width one of two modifier classes. To proportionately fill all available space use layout="fill". Notice that all horizontal space is occupied, but not every nav item has the same width.

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey={2}>
<CTabList variant="tabs" layout="fill">
<CTab aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab aria-controls="profile-tab-pane" itemKey={2}>Profile tab with longer content</CTab>
<CTab aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="py-3" aria-labelledby="home-tab-pane" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="profile-tab-pane" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="contact-tab-pane" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="disabled-tab-pane" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

For equal-width elements, use layout="justified". All horizontal space will be occupied by nav links, but unlike the layout="fill" above, every nav item will be the same width.

Home tab content
Profile tab content
Contact tab content
Disabled tab content
<CTabs activeItemKey={2}>
<CTabList variant="tabs" layout="justified">
<CTab aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab aria-controls="profile-tab-pane" itemKey={2}>Profile</CTab>
<CTab aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel className="py-3" aria-labelledby="home-tab-pane" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="profile-tab-pane" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="contact-tab-pane" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel className="py-3" aria-labelledby="disabled-tab-pane" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

Accessibility#

Dynamic tabbed interfaces, as described in the WAI ARIA Authoring Practices, require role="tablist", role="tab", role="tabpanel", and additional aria- attributes in order to 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.

Our React 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. Additionally, you have the flexibility to manually set these attributes, as shown in the example below:

<CTabs activeItemKey={2}>
<CTabList variant="tabs">
<CTab id="home-tab" aria-controls="home-tab-pane" itemKey={1}>Home</CTab>
<CTab id="profile-tab" aria-controls="profile-tab-pane" itemKey={2}>Profile</CTab>
<CTab id="contact-tab" aria-controls="contact-tab-pane" itemKey={3}>Contact</CTab>
<CTab id="disabled-tab" aria-controls="disabled-tab-pane" disabled itemKey={4}>Disabled</CTab>
</CTabList>
<CTabContent>
<CTabPanel id="home-tab-pane" className="p-3" aria-labelledby="home-tab-pane" aria-labelledby="home-tab" itemKey={1}>
Home tab content
</CTabPanel>
<CTabPanel id="profile-tab-pane" className="p-3" aria-labelledby="profile-tab-pane" aria-labelledby="profile-tab" itemKey={2}>
Profile tab content
</CTabPanel>
<CTabPanel id="contact-tab-pane" className="p-3" aria-labelledby="contact-tab-pane" aria-labelledby="contact-tab" itemKey={3}>
Contact tab content
</CTabPanel>
<CTabPanel id="disabled-tab-pane" className="p-3" aria-labelledby="disabled-tab-pane" aria-labelledby="disabled-tab" itemKey={4}>
Disabled tab content
</CTabPanel>
</CTabContent>
</CTabs>

This example demonstrates how to manually set aria-selected, aria-controls, and aria-labelledby attributes on your <CTab>'s and <CTabPanels>'s.

Keyboard Interaction#

When focus enters the tab list:

Tab: It places focus on the active tab element.

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 tab. If on the first tab, it wraps around to the last tab.

Right Arrow: Moves focus to the next tab. If on the last tab, it wraps around to the first tab.

Home: Moves focus to the first tab.

End: Moves focus to the last tab.

Customizing#

CSS variables#

React 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 modifier class:

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

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"
}
return <CTabs style={vars}>...</CTabs>

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#

CTab#

import { CTab } from '@coreui/react'
// or
import CTab from '@coreui/react/src/components/tabs/CTab'
PropertyDescriptionTypeDefault
classNameA string of all className you want applied to the base component.string-
itemKeyItem key.string | number-

CTabContent#

import { CTabContent } from '@coreui/react'
// or
import CTabContent from '@coreui/react/src/components/tabs/CTabContent'
PropertyDescriptionTypeDefault
classNameA string of all className you want applied to the base component.string-

CTabList#

import { CTabList } from '@coreui/react'
// or
import CTabList from '@coreui/react/src/components/tabs/CTabList'
PropertyDescriptionTypeDefault
classNameA string of all className you want applied to the base component.string-
layoutSpecify a layout type for component.'fill' | 'justified'-
variantSet the nav variant to tabs or pills.'pills' | 'tabs' | 'underline' | 'underline-border'-

CTabPanel#

import { CTabPanel } from '@coreui/react'
// or
import CTabPanel from '@coreui/react/src/components/tabs/CTabPanel'
PropertyDescriptionTypeDefault
classNameA string of all className you want applied to the base component.string-
itemKeyItem key.string | number-
onHideCallback fired when the component requests to be hidden.() => void-
onShowCallback fired when the component requests to be shown.() => void-
transitionEnable fade in and fade out transition.booleantrue
visibleToggle the visibility of component.boolean-

CTabs#

import { CTabs } from '@coreui/react'
// or
import CTabs from '@coreui/react/src/components/tabs/CTabs'
PropertyDescriptionTypeDefault
activeItemKeyThe active item key.string | number-
classNameA string of all className you want applied to the base component.string-
onChangeThe callback is fired when the active tab changes.(value: string | number) => void-