Version 0.13.2

Tabs

A tabbed interface supporting local state and URL-based navigation.

Content for Tab 1

Usage#

import { Tabs, TabList, Tab, TabPanel } from '@backstage/ui';

<Tabs>
  <TabList>
    <Tab id="tab1">Tab 1</Tab>
    <Tab id="tab2">Tab 2</Tab>
  </TabList>
  <TabPanel id="tab1">Content 1</TabPanel>
  <TabPanel id="tab2">Content 2</TabPanel>
</Tabs>

API reference#

Tabs#

Container that groups the tab list and panels.

PropTypeDefaultDescription
orientation
horizontalvertical
horizontalLayout direction. Use horizontal for top navigation, vertical for sidebar-style.
selectedKey
string
-The currently selected tab key (controlled).
defaultSelectedKey
string
-The default selected tab key (uncontrolled).
onSelectionChange
(key: Key) => void
-Handler called when the selected tab changes.
isDisabled
boolean
falseDisables all tabs. Use when an entire section is unavailable.
disabledKeys
Iterable<Key>
-Keys of tabs that should be disabled.
children
ReactNode
-
className
string
-Additional CSS class name for custom styling.

Inherits all React Aria Tabs props.

TabList#

Container for the tab buttons.

PropTypeDefaultDescription
children
ReactNode
-
className
string
-Additional CSS class name for custom styling.

Inherits all React Aria TabList props.

Tab#

Individual tab button. Add href to enable URL-based tab selection.

PropTypeDefaultDescription
id
string
-Unique identifier matching the corresponding TabPanel.
href
string
-URL to navigate to. When set, tab selection is controlled by the current route.
matchStrategy
exactprefix
exactURL matching strategy. Use exact for leaf routes, prefix for parent routes.
isDisabled
boolean
falseDisables this tab. Use for temporarily unavailable options.
noTrack
boolean
-Suppresses the automatic analytics click event, e.g. if you already have custom tracking.
children
ReactNode
-
className
string
-Additional CSS class name for custom styling.

Inherits all React Aria Tab props.

TabPanel#

Content panel associated with a tab.

PropTypeDefaultDescription
id
string
-Unique identifier matching the corresponding Tab.
children
ReactNode
-
className
string
-Additional CSS class name for custom styling.

Inherits all React Aria TabPanel props.

Examples#

Default selected#

<Tabs defaultSelectedKey="tab2">
  <TabList>
    <Tab id="tab1">Tab 1</Tab>
    <Tab id="tab2">Tab 2</Tab>
    <Tab id="tab3">Tab 3</Tab>
  </TabList>
  <TabPanel id="tab1">Content 1</TabPanel>
  <TabPanel id="tab2">Content 2</TabPanel>
  <TabPanel id="tab3">Content 3</TabPanel>
</Tabs>
Content for Tab 2

Disabled tabs#

<Tabs>
  <TabList>
    <Tab id="tab1">Tab 1</Tab>
    <Tab id="tab2" isDisabled>Tab 2 (Disabled)</Tab>
    <Tab id="tab3">Tab 3</Tab>
  </TabList>
  <TabPanel id="tab1">Content 1</TabPanel>
  <TabPanel id="tab2">Content 2</TabPanel>
  <TabPanel id="tab3">Content 3</TabPanel>
</Tabs>
Content for Tab 1

Vertical orientation#

<Tabs orientation="vertical">
  <TabList>
    <Tab id="tab1">Tab 1</Tab>
    <Tab id="tab2">Tab 2</Tab>
    <Tab id="tab3">Tab 3</Tab>
  </TabList>
  <TabPanel id="tab1">Content 1</TabPanel>
  <TabPanel id="tab2">Content 2</TabPanel>
  <TabPanel id="tab3">Content 3</TabPanel>
</Tabs>
Content for Tab 1

URL-based navigation#

Add href to Tab components to enable URL-based tab selection. The active tab is determined by the current route.

<Tabs>
  <TabList>
    <Tab id="overview" href="/settings/overview">Overview</Tab>
    <Tab id="profile" href="/settings/profile">Profile</Tab>
    <Tab id="security" href="/settings/security">Security</Tab>
  </TabList>
  <TabPanel id="overview">Overview content</TabPanel>
  <TabPanel id="profile">Profile content</TabPanel>
  <TabPanel id="security">Security content</TabPanel>
</Tabs>

Theming#

Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below.

  • bui-Tabs

Changelog#

Version 0.13.0#

Breaking Changes

  • Tabs Breaking Centralized client-side routing in BUIProvider. Components like Link, ButtonLink, Tabs, Menu, TagGroup, and Table now require a BUIProvider rendered inside a React Router context for client-side navigation to work. #33267

    Migration Guide:

    This change requires updating @backstage/plugin-app and @backstage/core-app-api alongside @backstage/ui. If you only upgrade @backstage/ui, BUI components will fall back to full-page navigation.

    If you cannot upgrade all packages together, or if you have a custom app shell, add a BUIProvider inside your Router:

    + import { BUIProvider } from '@backstage/ui';
    
      <BrowserRouter>
    +   <BUIProvider>
          <AppContent />
    +   </BUIProvider>
      </BrowserRouter>
    

Changes

  • Tab Added analytics capabilities to the component library. Components with navigation behavior (Link, ButtonLink, Tab, MenuItem, Tag, Row) now fire analytics events on click when a BUIProvider is present.

    New exports: BUIProvider, useAnalytics, getNodeText, and associated types (AnalyticsTracker, UseAnalyticsFn, BUIProviderProps, AnalyticsEventAttributes).

    Components with analytics support now accept a noTrack prop to suppress event firing. #33150

  • Tabs Migrated all components from useStyles to useDefinition hook. Exported OwnProps types for each component, enabling better type composition for consumers. #33050

  • Tabs Fixed tab matchStrategy matching to ignore query parameters and hash fragments in tab href values. Previously, tabs with query params in their href (e.g., /page?group=foo) would never show as active since matching compared the full href string against location.pathname which never includes query params. #33047

Version 0.12.0#

Changes

  • Tabs Tab Fixed client-side navigation for container components by wrapping the container (not individual items) in RouterProvider. Components now conditionally provide routing context only when children have internal links, removing the Router context requirement when not needed. This also removes the need to wrap these components in MemoryRouter during tests when they are not using the href prop.

    Additionally, when multiple tabs match the current URL via prefix matching, the tab with the most specific path (highest segment count) is now selected. For example, with URL /catalog/users/john, a tab with path /catalog/users is now selected over a tab with path /catalog. #32373

Version 0.9.0#

Breaking Changes

  • Tabs Breaking Changed className prop behavior to augment default styles instead of being ignored or overriding them.

    If you were passing custom className values to any of these components that relied on the previous behavior, you may need to adjust your styles to account for the default classes now being applied alongside your custom classes. #31496