Tabs An accessible tabs component that provides keyboard interactions and ARIA
attributes described in the
WAI-ARIA Tabs Design Pattern .
import { Tabs , TabList , TabPanels , Tab , TabPanel } from "@chakra-ui/react"
Tabs : Provides context and state for all componentsTabList : Wrapper for the Tab
componentsTab : element that serves as a label for one of the tab panels and can be
activated to display that panel.TabPanels : Wrapper for the TabPanel
componentsTabPanel : element that contains the content associated with a tabYou can render any element within Tabs
, but TabList
should only have Tab
as children, and TabPanels
should have TabPanel
as children.
Tabs expects TabList
and TabPanels
as children. The order doesn't matter,
you can have TabList
at the top, at the bottom, or both.
< Tabs >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
< Tab > Three </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
< TabPanel >
< p > three ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Tabs come in 6 different variants to style the tabs: line
,enclosed
,
enclosed-colored
, soft-rounded
, solid-rounded
< Tabs variant = " enclosed " >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
You can also change the color scheme for any specific variant by passing the
colorScheme
.
The value of colorScheme
must exist in the theme object, and must be a key
in theme.colors
that has the 50
- 900
color values.
< Tabs variant = " soft-rounded " colorScheme = " green " >
< TabList >
< Tab > Tab 1 </ Tab >
< Tab > Tab 2 </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
You can change the size of the tab by passing size
prop. We support 3 sizes
sm
, md
, lg
< Tabs size = " md " variant = " enclosed " >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Changing the tabs alignment
# You can change the alignment of the TabList
by passing align
prop. We
support 3 sizes start
, center
, end
.
< Tabs align = " end " variant = " enclosed " >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Stretch the tab list to fit the container by passing isFitted
prop.
< Tabs isFitted variant = " enclosed " >
< TabList mb = " 1em " >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Styling the tab states via props
# In event you need to create custom styles for the tabs. Simply set the variant
to unstyled
, and use the _selected
, _hover
, _active
style props.
< Tabs variant = " unstyled " >
< TabList >
< Tab _selected = { { color : "white" , bg : "blue.500" } } > Tab 1 </ Tab >
< Tab _selected = { { color : "white" , bg : "green.400" } } > Tab 2 </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
The onChange
callback returns the active tab's index whenever the user changes
tabs. If you intend to control the tabs programmatically, use this with the
index
prop.
Red Teal Blue
The Primary Colors
Are 1, 2, 3
Red, yellow and blue.
function Example ( ) {
const colors = useColorModeValue (
[ "red.50" , "teal.50" , "blue.50" ] ,
[ "red.900" , "teal.900" , "blue.900" ] ,
)
const [ tabIndex , setTabIndex ] = React . useState ( 0 )
const bg = colors [ tabIndex ]
return (
< Tabs onChange = { ( index ) => setTabIndex ( index ) } bg = { bg } >
< TabList >
< Tab > Red </ Tab >
< Tab > Teal </ Tab >
< Tab > Blue </ Tab >
</ TabList >
< TabPanels p = " 2rem " >
< TabPanel > The Primary Colors </ TabPanel >
< TabPanel > Are 1 , 2 , 3 </ TabPanel >
< TabPanel > Red , yellow and blue . </ TabPanel >
</ TabPanels >
</ Tabs >
)
}
copy Editable Example
Make a tab initially active
# If you want a tab to be initially active, simply pass the defaultIndex
prop
and set it to the index of that tab.
< Tabs defaultIndex = { 1 } >
< TabPanels >
< TabPanel >
< Image
boxSize = " 200px "
fit = " cover "
src = " https://resizing.flixster.com/wTgvsiM8vNLhCcCH-6ovV8n5z5U=/300x300/v1.bjsyMDkxMzI5O2o7MTgyMDQ7MTIwMDsxMjAwOzkwMA "
/>
</ TabPanel >
< TabPanel >
< Image
boxSize = " 200px "
fit = " cover "
src = " https://vignette.wikia.nocookie.net/naruto/images/2/21/Sasuke_Part_1.png/revision/latest?cb=20170716092103 "
/>
</ TabPanel >
</ TabPanels >
< TabList >
< Tab > Naruto </ Tab >
< Tab > Sasuke </ Tab >
</ TabList >
</ Tabs >
copy Editable Example
When a Tab
is disabled, it is skipped during keyboard navigation and it is not
clickable.
function Example ( ) {
return (
< Tabs >
< TabList >
< Tab > One </ Tab >
< Tab isDisabled > Two </ Tab >
< Tab > Three </ Tab >
</ TabList >
< TabPanels >
< TabPanel > 1 </ TabPanel >
< TabPanel > 2 </ TabPanel >
< TabPanel > 3 </ TabPanel >
</ TabPanels >
</ Tabs >
)
}
copy Editable Example
Tabs with manual activation
# By default, Tabs
are activated automatically. This means when you use the
arrow keys to change tabs, the tab is activated and focused.
The content of a TabPanel
should ideally be preloaded. However, if switching
to a tab panel causes a network request and possibly a page refresh, there
might be some noticable latency and this might affect the experience for
keyboard and screen reader users.
In this scenario, you should use a manually activated tab, it moves focus
without activating the tabs. With focus on a specific tab, users can activate a
tab by pressing Space or Enter .
< Tabs isManual variant = " enclosed " >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > one ! </ p >
</ TabPanel >
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Lazily mounting tab panels
# By default, the Tabs
component renders all tabs content to the DOM, meaning
that invisible tabs are still rendered but are hidden by styles.
If you want to defer rendering of each tab until that tab is selected, you can
use the isLazy
prop. This is useful if your tabs require heavy performance, or
make network calls on mount that should only happen when the component is
displayed.
< Tabs isLazy >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
</ TabList >
< TabPanels >
{ }
< TabPanel >
< p > one ! </ p >
</ TabPanel >
{ }
< TabPanel >
< p > two ! </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
copy Editable Example
Like form inputs, a tab's state can be controlled. Make sure to include an
onChange as well, or else the tabs will not be interactive.
function ControlledExample ( ) {
const [ tabIndex , setTabIndex ] = React . useState ( 0 )
const handleSliderChange = ( event ) => {
setTabIndex ( parseInt ( event . target . value , 10 ) )
}
const handleTabsChange = ( index ) => {
setTabIndex ( index )
}
return (
< Box >
< input
type = " range "
min = " 0 "
max = " 2 "
value = { tabIndex }
onChange = { handleSliderChange }
/>
< Tabs index = { tabIndex } onChange = { handleTabsChange } >
< TabList >
< Tab > One </ Tab >
< Tab > Two </ Tab >
< Tab > Three </ Tab >
</ TabList >
< TabPanels >
< TabPanel >
< p > Click the tabs or pull the slider around </ p >
</ TabPanel >
< TabPanel >
< p > Yeah yeah . What's up ? </ p >
</ TabPanel >
< TabPanel >
< p > Oh , hello there . </ p >
</ TabPanel >
</ TabPanels >
</ Tabs >
</ Box >
)
}
copy Editable Example
Creating custom tab components
# Because TabList
needs to know the order of the children, we use cloneElement
to pass state internally. Your custom Tab
component must use
React.forwardRef
.
function CustomTabs ( ) {
const StyledTab = chakra ( "button" , { themeKey : "Tabs.Tab" } )
const CustomTab = React . forwardRef ( ( props , ref ) => {
const tabProps = useTab ( props )
const isSelected = ! ! tabProps [ "aria-selected" ]
const styles = useStyles ( )
return (
< StyledTab __css = { styles . tab } { ... tabProps } >
< Box as = " span " mr = " 2 " >
{ isSelected ? "😎" : "😐" }
</ Box >
{ tabProps . children }
</ StyledTab >
)
} )
return (
< Tabs >
< TabList >
< CustomTab > One </ CustomTab >
< CustomTab > Two </ CustomTab >
</ TabList >
< TabPanels >
< TabPanel > 1 </ TabPanel >
< TabPanel > 2 </ TabPanel >
</ TabPanels >
</ Tabs >
)
}
copy Editable Example
If you'd like to drive your tabs with an array instead of using the granular
components, you can create your own DataTabs component.
Nigerian Jollof Pounded Yam & Egusi
Perhaps the greatest dish ever invented.
Perhaps the surest dish ever invented but fills the stomach more than rice.
function Example ( ) {
function DataTabs ( { data } ) {
return (
< Tabs >
< TabList >
{ data . map ( ( tab , index ) => (
< Tab key = { index } > { tab . label } </ Tab >
) ) }
</ TabList >
< TabPanels >
{ data . map ( ( tab , index ) => (
< TabPanel p = { 4 } key = { index } >
{ tab . content }
</ TabPanel >
) ) }
</ TabPanels >
</ Tabs >
)
}
const tabData = [
{
label : "Nigerian Jollof" ,
content : "Perhaps the greatest dish ever invented." ,
} ,
{
label : "Pounded Yam & Egusi" ,
content :
"Perhaps the surest dish ever invented but fills the stomach more than rice." ,
} ,
]
return < DataTabs data = { tabData } />
}
copy Editable Example
Key Action ArrowLeft
Moves focus to the next tab ArrowUp
Moves focus to the previous tab Tab
When focus moves into the tab list, places focus on the active tab element Space
or Enter
Activates the tab if it was not activated automatically on focus Home
Moves focus to the first tab End
Moves focus to the last tab
Component Aria Usage Tab role="tab"
Indicates that it is a tab aria-selected
Set to true
a tab is selected and all other Tabs have it set to false
. aria-controls
Set to the id
of its associated TabPanel
TabList id
The id
of the TabPanel
that's referencd by its associated Tab
aria-orientation
Set to vertical or horizontal based on the value of the orientation
prop. role="tablist"
Indicates that it is a tablist aria-labelledby
Set to the id
of the Tab
that labels the TabPanel
.
Tabs composes Box
so you call pass all Box
related props.
Name Type Description Default align "center" | "end" | "start"
The alignment of the tabs - colorScheme string
- css Interpolation<{}>
The emotion's css style object - defaultIndex number
The initial index of the selected tab (in uncontrolled mode) - id string
The id of the tab - index number
The index of the selected tab (in controlled mode) - isFitted boolean
If `true`, tabs will stretch to width of the tablist. - isLazy boolean
Performance 🚀:
If `true`, the TabPanel rendering will be deferred
until it is open. - isManual boolean
If `true`, the tabs will be manually activated and
display its panel by pressing Space or Enter.
If `false`, the tabs will be automatically activated
and their panel is displayed when they receive focus. - onChange ((index: number) => void)
Callback when the index (controlled or un-controlled) changes. - orientation "horizontal" | "vertical"
The orientation of the tab list. - size string
- styleConfig Record<string, any>
- variant string
-
Name Type Description Default css Interpolation<{}>
The emotion's css style object - id string
- isDisabled boolean
If `true`, the `Tab` won't be toggleable - isSelected boolean
- panelId string
-