Skip to content

Tabs

Tabs make it easy to explore and switch between different views.

Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.

Basic tabs

A basic example with tab panels.

Item One

<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
  <Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
    <Tab label="Item One" {...a11yProps(0)} />
    <Tab label="Item Two" {...a11yProps(1)} />
    <Tab label="Item Three" {...a11yProps(2)} />
  </Tabs>
</Box>
<TabPanel value={value} index={0}>
  Item One
</TabPanel>
<TabPanel value={value} index={1}>
  Item Two
</TabPanel>
<TabPanel value={value} index={2}>
  Item Three
</TabPanel>

Experimental API

@mui/lab offers utility components that inject props to implement accessible tabs following WAI-ARIA authoring practices.

Item One
<TabContext value={value}>
  <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
    <TabList onChange={handleChange} aria-label="lab API tabs example">
      <Tab label="Item One" value="1" />
      <Tab label="Item Two" value="2" />
      <Tab label="Item Three" value="3" />
    </TabList>
  </Box>
  <TabPanel value="1">Item One</TabPanel>
  <TabPanel value="2">Item Two</TabPanel>
  <TabPanel value="3">Item Three</TabPanel>
</TabContext>

Wrapped labels

Long labels will automatically wrap on tabs. If the label is too long for the tab, it will overflow, and the text will not be visible.

<Tabs
  value={value}
  onChange={handleChange}
  aria-label="wrapped label tabs example"
>
  <Tab
    value="one"
    label="New Arrivals in the Longest Text of Nonfiction that should appear in the next line"
    wrapped
  />
  <Tab value="two" label="Item Two" />
  <Tab value="three" label="Item Three" />
</Tabs>

Colored tab

<Tabs
  value={value}
  onChange={handleChange}
  textColor="secondary"
  indicatorColor="secondary"
  aria-label="secondary tabs example"
>
  <Tab value="one" label="Item One" />
  <Tab value="two" label="Item Two" />
  <Tab value="three" label="Item Three" />
</Tabs>

Disabled tab

A tab can be disabled by setting the disabled prop.

<Tabs value={value} onChange={handleChange} aria-label="disabled tabs example">
  <Tab label="Active" />
  <Tab label="Disabled" disabled />
  <Tab label="Active" />
</Tabs>

Fixed tabs

Fixed tabs should be used with a limited number of tabs, and when a consistent placement will aid muscle memory.

Full width

The variant="fullWidth" prop should be used for smaller views. This demo also uses react-swipeable-views to animate the Tab transition, and allowing tabs to be swiped on touch devices.

Item One

Centered

The centered prop should be used for larger views.

<Tabs value={value} onChange={handleChange} centered>
  <Tab label="Item One" />
  <Tab label="Item Two" />
  <Tab label="Item Three" />
</Tabs>

Scrollable tabs

Automatic scroll buttons

By default, left and right scroll buttons are automatically presented on desktop and hidden on mobile. (based on viewport width)

<Tabs
  value={value}
  onChange={handleChange}
  variant="scrollable"
  scrollButtons="auto"
  aria-label="scrollable auto tabs example"
>
  <Tab label="Item One" />
  <Tab label="Item Two" />
  <Tab label="Item Three" />
  <Tab label="Item Four" />
  <Tab label="Item Five" />
  <Tab label="Item Six" />
  <Tab label="Item Seven" />
</Tabs>

Forced scroll buttons

Left and right scroll buttons be presented (reserve space) regardless of the viewport width with scrollButtons={true} allowScrollButtonsMobile:

<Tabs
  value={value}
  onChange={handleChange}
  variant="scrollable"
  scrollButtons
  allowScrollButtonsMobile
  aria-label="scrollable force tabs example"
>
  <Tab label="Item One" />
  <Tab label="Item Two" />
  <Tab label="Item Three" />
  <Tab label="Item Four" />
  <Tab label="Item Five" />
  <Tab label="Item Six" />
  <Tab label="Item Seven" />
</Tabs>

If you want to make sure the buttons are always visible, you should customize the opacity.

.MuiTabs-scrollButtons.Mui-disabled {
  opacity: 0.3;
}

Prevent scroll buttons

Left and right scroll buttons are never be presented with scrollButtons={false}. All scrolling must be initiated through user agent scrolling mechanisms (e.g. left/right swipe, shift mouse wheel, etc.)

<Tabs
  value={value}
  onChange={handleChange}
  variant="scrollable"
  scrollButtons={false}
  aria-label="scrollable prevent tabs example"
>
  <Tab label="Item One" />
  <Tab label="Item Two" />
  <Tab label="Item Three" />
  <Tab label="Item Four" />
  <Tab label="Item Five" />
  <Tab label="Item Six" />
  <Tab label="Item Seven" />
</Tabs>

Customization

Here is an example of customizing the component. You can learn more about this in the overrides documentation page.

🎨 If you are looking for inspiration, you can check MUI Treasury's customization examples.

Vertical tabs

To make vertical tabs instead of default horizontal ones, there is orientation="vertical":

Item One

Note that you can restore the scrollbar with visibleScrollbar.

Nav tabs

By default, tabs use a button element, but you can provide your custom tag or component. Here's an example of implementing tabbed navigation:

<Tabs value={value} onChange={handleChange} aria-label="nav tabs example">
  <LinkTab label="Page One" href="/drafts" />
  <LinkTab label="Page Two" href="/trash" />
  <LinkTab label="Page Three" href="/spam" />
</Tabs>

Icon tabs

Tab labels may be either all icons or all text.

<Tabs value={value} onChange={handleChange} aria-label="icon tabs example">
  <Tab icon={<PhoneIcon />} aria-label="phone" />
  <Tab icon={<FavoriteIcon />} aria-label="favorite" />
  <Tab icon={<PersonPinIcon />} aria-label="person" />
</Tabs>
<Tabs value={value} onChange={handleChange} aria-label="icon label tabs example">
  <Tab icon={<PhoneIcon />} label="RECENTS" />
  <Tab icon={<FavoriteIcon />} label="FAVORITES" />
  <Tab icon={<PersonPinIcon />} label="NEARBY" />
</Tabs>

Icon position

By default, the icon is positioned at the top of a tab. Other supported positions are start, end, bottom.

<Tabs
  value={value}
  onChange={handleChange}
  aria-label="icon position tabs example"
>
  <Tab icon={<PhoneIcon />} label="top" />
  <Tab icon={<PhoneMissedIcon />} iconPosition="start" label="start" />
  <Tab icon={<FavoriteIcon />} iconPosition="end" label="end" />
  <Tab icon={<PersonPinIcon />} iconPosition="bottom" label="bottom" />
</Tabs>

Third-party routing library

One frequent use case is to perform navigation on the client only, without an HTTP round-trip to the server. The Tab component provides the component prop to handle this use case. Here is a more detailed guide.

Accessibility

(WAI-ARIA: https://www.w3.org/TR/wai-aria-practices/#tabpanel)

The following steps are needed in order to provide necessary information for assistive technologies:

  1. Label Tabs via aria-label or aria-labelledby.
  2. Tabs need to be connected to their corresponding [role="tabpanel"] by setting the correct id, aria-controls and aria-labelledby.

An example for the current implementation can be found in the demos on this page. We've also published an experimental API in @mui/lab that does not require extra work.

Keyboard navigation

The components implement keyboard navigation using the "manual activation" behavior. If you want to switch to the "selection automatically follows focus" behavior you have pass selectionFollowsFocus to the Tabs component. The WAI-ARIA authoring practices have a detailed guide on how to decide when to make selection automatically follow focus.

Demo

The following two demos only differ in their keyboard navigation behavior. Focus a tab and navigate with arrow keys to notice the difference, e.g. Arrow Left.

/* Tabs where selection follows focus */
<Tabs selectionFollowsFocus />
/* Tabs where each tab needs to be selected manually */
<Tabs />

Unstyled

The Tabs also come with an unstyled version. It's ideal for doing heavy customizations and minimizing bundle size.

Unstyled component

import TabsUnstyled from '@mui/base/TabsUnstyled';
import TabsListUnstyled from '@mui/base/TabUnstyled';
import TabUnstyled from '@mui/base/TabUnstyled';
import TabPanelUnstyled from '@mui/base/TabPanelUnstyled';
First content
<TabsUnstyled defaultValue={0}>
  <TabsListUnstyled>
    <TabUnstyled>One</TabUnstyled>
    <TabUnstyled>Two</TabUnstyled>
    <TabUnstyled>Three</TabUnstyled>
  </TabsListUnstyled>
  <TabPanelUnstyled value={0}>First content</TabPanelUnstyled>
  <TabPanelUnstyled value={1}>Second content</TabPanelUnstyled>
  <TabPanelUnstyled value={2}>Third content</TabPanelUnstyled>
</TabsUnstyled>

Customizing the root element

By default, the TabUnstyled renders a native button element. You are free to override this by setting the component or components.Root prop. If a non-interactive element (such as a span) is provided this way, the TabUnstyled will take care of adding accessibility attributes.

The TabPanelUnstyled on the other hand renders a native div element by default. You are free to override this as well by setting the component or components.Root prop on the TabPanelUnstyled.

First content
<TabsUnstyled defaultValue={0}>
  <TabsList>
    <Tab>One</Tab>
    <Tab>Two</Tab>
    <Tab>Three</Tab>
  </TabsList>
  <TabPanel value={0}>First content</TabPanel>
  <TabPanel value={1}>Second content</TabPanel>
  <TabPanel value={2}>Third content</TabPanel>
</TabsUnstyled>