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.
Other frameworks
CoreUI components are available as native Angular, Bootstrap (Vanilla JS), and Vue components. To learn more please visit the following pages.
Example#
The basic React tabs example uses the variant="tabs"
props to generate a tabbed interface.
<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.
<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:
<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:
<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:
<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.
<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.
<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 roletablist
. - 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
hasaria-labelledby
set to a value that refers to the labeling element. Otherwise, thetablist
element has a label provided byaria-label
. - Each element with the role
tab
has the propertyaria-controls
referring to its associatedtabpanel
element. - The active tab element has the state
aria-selected
set totrue
, and all other tab elements have it set tofalse
. - Each element with the role
tabpanel
has the propertyaria-labelledby
referring to its associatedtab
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'// orimport CTab from '@coreui/react/src/components/tabs/CTab'
Property | Description | Type | Default |
---|---|---|---|
className | A string of all className you want applied to the base component. | string | - |
disabled | Toggle the disabled state for the component. | boolean | - |
itemKey | Item key. | string | number | - |
CTabContent#
import { CTabContent } from '@coreui/react'// orimport CTabContent from '@coreui/react/src/components/tabs/CTabContent'
Property | Description | Type | Default |
---|---|---|---|
className | A string of all className you want applied to the base component. | string | - |
CTabList#
import { CTabList } from '@coreui/react'// orimport CTabList from '@coreui/react/src/components/tabs/CTabList'
Property | Description | Type | Default |
---|---|---|---|
className | A string of all className you want applied to the base component. | string | - |
layout | Specify a layout type for component. | 'fill' | 'justified' | - |
variant | Set the nav variant to tabs or pills. | 'pills' | 'tabs' | 'underline' | 'underline-border' | - |
CTabPanel#
import { CTabPanel } from '@coreui/react'// orimport CTabPanel from '@coreui/react/src/components/tabs/CTabPanel'
Property | Description | Type | Default |
---|---|---|---|
className | A string of all className you want applied to the base component. | string | - |
itemKey | Item key. | string | number | - |
onHide | Callback fired when the component requests to be hidden. | () => void | - |
onShow | Callback fired when the component requests to be shown. | () => void | - |
transition | Enable fade in and fade out transition. | boolean | true |
visible | Toggle the visibility of component. | boolean | - |
CTabs#
import { CTabs } from '@coreui/react'// orimport CTabs from '@coreui/react/src/components/tabs/CTabs'
Property | Description | Type | Default |
---|---|---|---|
activeItemKey | The active item key. | string | number | - |
className | A string of all className you want applied to the base component. | string | - |
onChange | The callback is fired when the active tab changes. | (value: string | number) => void | - |