Tabs
A React component that helps you build accessible tabs, by providing keyboard interactions and ARIA attributes described in the WAI-ARIA Tab Panel Design Pattern.
Import#
import { Tabs } from '@chakra-ui/react'
Usage#
Tab requires the value
prop to be passed to both the Tabs.Trigger
and the
Tabs.Content
components. This is used to associate the tab with its content.
<Tabs.Root defaultValue='one'><Tabs.List><Tabs.Trigger value='one'>One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger><Tabs.Trigger value='three'>Three</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content><Tabs.Content value='three'><p>three!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Changing the variant#
Tabs come in 6 different variants to style the tabs: line
,enclosed
,
outline
, and plain
<Tabs.Root defaultValue='one'><Tabs.List><Tabs.Trigger value='one'>One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Changing the color palette#
Set the colorPalette
prop to change the color of the tabs. This will change
the color of the active tab and the active tab indicator.
<Tabs.Root defaultValue='one' colorPalette='teal'><Tabs.List><Tabs.Trigger value='one'>Tab 1</Tabs.Trigger><Tabs.Trigger value='two'>Tab 2</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Changing the size of the tab#
You can change the size of the tab by passing size
prop. We support 3 sizes
sm
, md
, lg
<Tabs.Root defaultValue='one' size='sm'><Tabs.List><Tabs.Trigger value='one'>Tab 1</Tabs.Trigger><Tabs.Trigger value='two'>Tab 2</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Changing the alignment of the tab list#
You can change the alignment of the TabList
by passing justify
prop. The
values are start
, center
, end
.
<Tabs.Root defaultValue='one' justify='end'><Tabs.List><Tabs.Trigger value='one'>Tab 1</Tabs.Trigger><Tabs.Trigger value='two'>Tab 2</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Fitted Tabs#
Stretch the tab list to fit the container by passing fitted
prop.
<Tabs.Root defaultValue='one' fitted><Tabs.List><Tabs.Trigger value='one'>Tab 1</Tabs.Trigger><Tabs.Trigger value='two'>Tab 2</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Rendering an indicator#
You can render a custom indicator by rendering the Tabs.Indicator
component
within the Tabs.List
component.
<Tabs.Root defaultValue='one' unstyled><Tabs.List><Tabs.Trigger value='one'> One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger><Tabs.Trigger value='three'>Three</Tabs.Trigger><Tabs.Indicator mt='-1.5px' height='2px' bg='teal.600' borderRadius='1px' /></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content><Tabs.Content value='three'><p>three!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Styling the tab states via props#
In the event that you need to create custom styles for individual tabs, use the
_selected
, _hover
, _active
style props.
<Tabs.Root defaultValue='one' variant='unstyled'><Tabs.List><Tabs.Trigger value='one' _selected={{ color: 'white', bg: 'blue.500' }}>Tab 1</Tabs.Trigger><Tabs.Trigger value='two' _selected={{ color: 'white', bg: 'green.400' }}>Tab 2</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Listening to tab changes#
The onChange
callback returns the active tab's value whenever the user changes
tabs.
<Tabs.Root defaultValue='red' onChange={(value) => setValue(value)}><Tabs.List><Tabs.Trigger value='red'>Red</Tabs.Trigger><Tabs.Trigger value='teal'>Teal</Tabs.Trigger><Tabs.Trigger value='blue'>Blue</Tabs.Trigger></Tabs.List><Tabs.ContentGroup p='2rem'><Tabs.Content value='red'>The Primary Colors</Tabs.Content><Tabs.Content value='teal'>Are 1, 2, 3</Tabs.Content><Tabs.Content value='blue'>Red, yellow and blue.</Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Setting the initially selected tab#
If you want a tab to be initially active, simply pass the defaultValue
prop
<Tabs.Root defaultValue='naruto'><Tabs.ContentGroup><Tabs.Content value='naruto'><ImageboxSize='200px'fit='cover'src='https://www.freepnglogos.com/uploads/naruto-png/image-kunai-naruto-fictional-battle-omniverse-23.png'/></Tabs.Content><Tabs.Content value='sasuke'><ImageboxSize='200px'fit='cover'src='https://images5.alphacoders.com/810/thumbbig-810547.webp'/></Tabs.Content></Tabs.ContentGroup><Tabs.List><Tabs.Trigger value='naruto'>Naruto</Tabs.Trigger><Tabs.Trigger value='sasuke'>Sasuke</Tabs.Trigger></Tabs.List></Tabs.Root>
Disabling a tab#
When a Tabs.Trigger
is disabled, it is skipped during keyboard navigation and
it is not clickable.
function Example() {return (<Tabs.Root defaultValue='one'><Tabs.List><Tabs.Trigger value="one">One</Tabs.Trigger><Tabs.Trigger disabled value="two">Two</Tabs.Trigger><Tabs.Trigger value="three">Three</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value="one">1</Tabs.Conte><Tabs.Content value="two">2</Tabs.Conte><Tabs.Content value="three">3</Tabs.Conte></Tabs.ContentGroup></Tabs.Root>)}
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.
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.Root defaultValue='one' activationMode='manual'><Tabs.List><Tabs.Trigger value='one'>One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
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.
Set the lazyMount
prop to defer rendering of each tab until that tab is
selected.
This is useful if your tabs require heavy performance
<Tabs.Root defaultValue='one' lazyMount><Tabs.List><Tabs.Trigger value='one'>One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>one!</p></Tabs.Content><Tabs.Content value='two'><p>two!</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>
Controlled Tabs#
To control the selected tab programmatically, you can pass the value
and
onChange
props to the Tabs.Root
component.
function ControlledExample() {const [value, setValue] = useState('one')const tabs = ['one', 'two', 'three']return (<Tabs.Root defaultValue='one' value={value} onChange={setValue}><Tabs.List><Tabs.Trigger value='one'>One</Tabs.Trigger><Tabs.Trigger value='two'>Two</Tabs.Trigger><Tabs.Trigger value='three'>Three</Tabs.Trigger></Tabs.List><Tabs.ContentGroup><Tabs.Content value='one'><p>Click the tabs or pull the slider around</p></Tabs.Content><Tabs.Content value='two'><p>Yeah yeah. What's up?</p></Tabs.Content><Tabs.Content value='three'><p>Oh, hello there.</p></Tabs.Content></Tabs.ContentGroup></Tabs.Root>)}
Accessibility#
Keyboard#
Key | Action |
---|---|
ArrowLeft | Moves focus to the next tab |
ArrowRight | 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 |
ARIA roles#
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 Tabs.Content | |
Tabs.Trigger | id | The id of the Tabs.Content that's referenced 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 | |
Tabs.Content | role="Tabs.Content" | Indicates that it is a Tabs.Content |
aria-labelledby | Set to the id of the Tab that labels the Tabs.Content |
The Tabs
component is a multipart component. The styling needs to be applied
to each part specifically.
To learn more about styling multipart components, visit the Component Style page.
Anatomy#
- A:
root
- B:
tab
- C:
tablist
- D:
tabpanels
- E:
tabpanel
Theming properties#
The properties that affect the theming of the Tabs
component are:
variant
: The visual variant of the component. Defaults toline
.size
: The size of the component. Defaults tomd
.colorScheme
: The color scheme of the component. Defaults toblue
.
Theming utilities#
createMultiStyleConfigHelpers
: a function that returns a set of utilities for creating style configs for a multipart component (definePartsStyle
anddefineMultiStyleConfig
).definePartsStyle
: a function used to create multipart style objects.defineMultiStyleConfig
: a function used to define the style configuration for a multipart component.
import { tabsAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(tabsAnatomy.keys)
Customizing the default theme#
import { tabsAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(tabsAnatomy.keys)// define the base component stylesconst baseStyle = definePartsStyle({// define the part you're going to styletab: {fontWeight: 'semibold', // change the font weight},tabpanel: {fontFamily: 'mono', // change the font family},})// export the component themeexport const tabsTheme = defineMultiStyleConfig({ baseStyle })
After customizing the the Tabs
theme, we can import it in our theme file and
add it in the components
property.
import { extendTheme } from '@chakra-ui/react'import { tabsTheme } from './components/Tabs'const theme = extendTheme({components: {Tabs: tabsTheme,},})export default theme
Adding a custom size#
Let's assume we want to include an extra large tab size. Here's how we can do that:
import { tabsAnatomy } from '@chakra-ui/anatomy';import { createMultiStyleConfigHelpers } from '@chakra-ui/react';const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(tabsAnatomy.keys);// define custom sizesconst sizes = {xl: definePartsStyle({// define the parts that will change for each sizetab: {fontSize: 'xl',py: '4',px: '6',},tabpanel: {py: '4',px: '6',},}),};// export the component themeexport const tabsTheme = defineMultiStyleConfig({ sizes });// now we can use the new `xl` size<Tabs size="xl" ... />
Every time you're adding anything new to the theme, you'd need to run the CLI command to get proper autocomplete in your IDE. You can learn more about the CLI tool here.
Adding a custom variant#
Let's assume we want to include a custom variant that is fully enclosed and can have a color scheme applied. Here's how we can do that:
import { tabsAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers } from '@chakra-ui/react'import { mode } from '@chakra-ui/theme-tools' // import utility to set light and dark mode props// define a custom variantconst colorfulVariant = definePartsStyle((props) => {const { colorScheme: c } = props // extract colorScheme from component propsreturn {tab: {border: '2px solid',borderColor: 'transparent',// use colorScheme to change background color with dark and light mode optionsbg: mode(`${c}.300`, `${c}.600`)(props),borderTopRadius: 'lg',borderBottom: 'none',_selected: {bg: mode('#fff', 'gray.800')(props),color: mode(`${c}.500`, `${c}.300`)(props),borderColor: 'inherit',borderBottom: 'none',mb: '-2px',},},tablist: {borderBottom: '2x solid',borderColor: 'inherit',},tabpanel: {border: '2px solid',borderColor: 'inherit',borderBottomRadius: 'lg',borderTopRightRadius: 'lg',},}})const variants = {colorful: colorfulVariant,}// export the component themeexport const tabsTheme = defineMultiStyleConfig({ variants })// now we can use the `colorful` variant with a different color Scheme<Tabs variant="colorful" colorPalette="purple" ... />
Changing the default properties#
Let's assume we want to change the default size, variant, and color scheme of every tab in our app. Here's how we can do that:
import { tabsAnatomy } from '@chakra-ui/anatomy';import { createMultiStyleConfigHelpers } from '@chakra-ui/react';// define which sizes, variants, and color schemes are applied by defaultconst defaultProps = {size: 'xl',variant: 'colorful',colorScheme: 'green',};// export the component themeexport const tabsTheme = defineMultiStyleConfig({ defaultProps })// This saves you time, instead of manually setting the// size and variant every time you use a tabs component:<Tabs size="xl" variant="colorful" colorPalette="green" ... />
Showcase#
import React from 'react'; import { ChakraProvider, Box, SimpleGrid, GridItem, Tabs, TabList, TabPanels, Tab, TabPanel, } from '@chakra-ui/react'; import theme from './theme'; import { ColorModeSwitcher } from './ColorModeSwitcher'; export default function App() { return ( <ChakraProvider theme={theme}> <Box position="relative" h="100vh" p={12}> <SimpleGrid columns={[1, 1, 1, 2]} spacing={12}> <GridItem> <Tabs> <TabList> <Tab>One</Tab> <Tab>Two</Tab> <Tab>Three</Tab> <Tab isDisabled>Disabled</Tab> </TabList> <TabPanels> <TabPanel> <p>New default appearance defined by theme</p> </TabPanel> <TabPanel> <p>Tab panel two</p> </TabPanel> <TabPanel> <p>Tab panel three</p> </TabPanel> </TabPanels> </Tabs> </GridItem> <GridItem> <Tabs size="lg" colorScheme="purple"> <TabList> <Tab>One</Tab> <Tab>Two</Tab> <Tab>Three</Tab> <Tab isDisabled>Disabled</Tab> </TabList> <TabPanels> <TabPanel> <p>Large size with purple color scheme</p> </TabPanel> <TabPanel> <p>Tab panel two</p> </TabPanel> <TabPanel> <p>Tab panel three</p> </TabPanel> </TabPanels> </Tabs> </GridItem> <GridItem> <Tabs size="md" colorScheme="cyan"> <TabList> <Tab>One</Tab> <Tab>Two</Tab> <Tab>Three</Tab> <Tab isDisabled>Disabled</Tab> </TabList> <TabPanels> <TabPanel> <p>Medium size with cyan color scheme</p> </TabPanel> <TabPanel> <p>Tab panel two</p> </TabPanel> <TabPanel> <p>Tab panel three</p> </TabPanel> </TabPanels> </Tabs> </GridItem> <GridItem> <Tabs size="sm" colorScheme="orange"> <TabList> <Tab>One</Tab> <Tab>Two</Tab> <Tab>Three</Tab> <Tab isDisabled>Disabled</Tab> </TabList> <TabPanels> <TabPanel> <p>Small size with orange color scheme</p> </TabPanel> <TabPanel> <p>Tab panel two</p> </TabPanel> <TabPanel> <p>Tab panel three</p> </TabPanel> </TabPanels> </Tabs> </GridItem> </SimpleGrid> <ColorModeSwitcher /> </Box> </ChakraProvider> ); }