Tabs

Tabs organize groups of related content and let users navigate between them.

Give FeedbackWAI-ARIABundle Size
My account page
index.tsx

Installation

Base UI components are all available as a single package.

npm install @base_ui/react

Once you have the package installed, import the component.

import { Tabs } from '@base_ui/react/Tabs';

Anatomy

Tabs are implemented using a collection of related components:

<Tabs.Root>
  <Tabs.List>
    <Tabs.Tab>One</Tabs.Tab>
    <Tabs.Tab>Two</Tabs.Tab>
    <Tabs.Indicator />
  </Tabs.List>
  <Tabs.Panel>First page</Tabs.Panel>
  <Tabs.Panel>Second page</Tabs.Panel>
</Tabs.Root>

Specifying values

By default, Tab components and their corresponding panels are zero-indexed. The first tab has a value of 0, the second tab has a value of 1, and so on. Activating a tab opens the panel with the same value, corresponding to the order in which each component is nested within its container.

Though not required, you can add the value prop to the Tab and Tab Panel to control how these components are associated.

<Tabs.Root defaultValue={1}>
  <Tabs.List>
    <Tabs.Tab value={1}>One</Tabs.Tab>
    <Tabs.Tab value={2}>Two</Tabs.Tab>
  </Tabs.List>
  <Tabs.Panel value={1}>First page</Tabs.Panel>
  <Tabs.Panel value={2}>Second page</Tabs.Panel>
</Tabs.Root>

Indicator

Though it's optional, the Tabs.Indicator component can be added to implement a visual indicator for the active tab. To help with styling—in particular animating its position—some CSS variables are provided.

Additionally, the Indicator has the data-activation-direction attribute representing the relation of the selected tab to the previously selected one. Its value is one of the following:

This example uses the CSS variables and data attributes described above to create an "elastic" movement effect.

IndicatorBubble.tsx

The next example shows a differently shaped Indicator with a simpler movement. As the transition is independent of direction, the data-activation-direction attribute is not used for styling.

IndicatorUnderline.tsx

Server rendering

The Indicator's rendering depends on React effects and cannot be done on the server. This means that if you're using server-side rendering (SSR), the initially rendered content will not contain the Indicator. It will appear after React hydrates the components.

If you want to minimize the time the Indicator is not visible, you can set the renderBeforeHydration prop to true. This will make the component include an inline script that sets the CSS variables as soon as it's rendered by the browser.

<Tabs.Indicator renderBeforeHydration />

It is disabled by default, as the script contributes to the size of the payload sent by the server.

Orientation

To arrange tabs vertically, set orientation="vertical" on the <Tabs /> component. Now, the user can navigate with the up and down arrow keys rather than the default left-to-right behavior for horizontal tabs.

Tabs can be rendered as links to routes in your application. A common use case for tabs is implementing client-side navigation that doesn't require an HTTP round-trip to the server.

Current route: /drafts

InboxDraftsTrash
UnstyledTabsRouting.tsx

Manual tab activation

By default, when using keyboard navigation, tabs are activated automatically when they receive focus. Alternatively, you can set activateOnFocus={false} on <Tabs.List> so tabs are not activated automatically when they receive focus.

<Tabs.List activateOnFocus={false} />

Overriding default components

Use the render prop to override the rendered element:

<Tabs.Tab render={<MyCustomTab />} />
// or
<Tabs.Tab render={(props) => <MyCustomTab {...props} />} />

If you provide a non-interactive element such as a <span>, the Tab components automatically add the necessary accessibility attributes.

Accessibility

Base UI Tabs follow the Tabs WAI-ARIA design pattern.

Keyboard navigation

KeyDescription
Left ArrowMoves focus to the previous tab (when orientation="horizontal") and activates it if activateOnFocus is set.
Right ArrowMoves focus to the next tab (when orientation="horizontal") and activates it if activateOnFocus is set.
Up ArrowMoves focus to the previous tab (when orientation="vertical") and activates it if activateOnFocus is set.
Down ArrowMoves focus to the next tab (when orientation="vertical") and activates it if activateOnFocus is set.
Space, EnterActivates the focused tab.

Labeling

To make the Tabs component suite accessible to assistive technology, label the <Tabs.List /> element with aria-label.

<Tabs>
  <Tabs.List aria-label="Seasons">
    <Tabs.Tab>Spring</Tabs.Tab>
    <Tabs.Tab>Summer</Tabs.Tab>
    <Tabs.Tab>Fall</Tabs.Tab>
    <Tabs.Tab>Winter</Tabs.Tab>
  </Tabs.List>
</Tabs>

API Reference

TabsRoot

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
defaultValueanyThe default value. Use when the component is not controlled.
directionenum'ltr'The direction of the text.
onValueChangefuncCallback invoked when new value is being set.
orientationenum'horizontal'The component orientation (layout flow direction).
renderunionA function to customize rendering of the component.
valueanyThe value of the currently selected Tab. If you don't want any selected Tab, you can set this prop to null.

TabPanel

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
keepMountedboolfalseIf true, keeps the contents of the hidden TabPanel in the DOM.
renderunionA function to customize rendering of the component.
valueanyThe value of the TabPanel. It will be shown when the Tab with the corresponding value is selected. If not provided, it will fall back to the index of the panel. It is recommended to explicitly provide it, as it's required for the tab panel to be rendered on the server.

Tab

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.
valueanyYou can provide your own value. Otherwise, it falls back to the child position index.

TabsList

PropTypeDefaultDescription
activateOnFocusbooltrueIf true, the tab will be activated whenever it is focused. Otherwise, it has to be activated by clicking or pressing the Enter or Space key.
classNameunionClass names applied to the element or a function that returns them based on the component's state.
loopbooltrueIf true, using keyboard navigation will wrap focus to the other end of the list once the end is reached.
renderunionA function to customize rendering of the component.

TabIndicator

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.
renderBeforeHydrationboolfalseIf true, the indicator will include code to render itself before React hydrates. This will minimize the time the indicator is not visible after the SSR-generated content is downloaded.

Contents