Tabs
Use tabs to organize related content into views that users can navigate between. Tabs enable users to switch between views while remaining within the same context on a page.
#Examples
The Tabs
component consists of two parts: the tabs and their contents. These two parts can either be nested within the same container (container-level tabs) or separate containers (page-level tabs). Furthermore, the contents of a tab is by default unmounted when a different tab is selected. However, it's also possible to keep tab contents mounted. Lastly, tab labels can be accompanied by both icons and badges. All these options are showcased in the following sections.
#Default
This is the default implementation of the Tabs
component. It doesn’t look great. This is partly because the content doesn't have any padding. This can be added by using a structure component, such as a Content component. However, the main reason is that Tabs
are meant to be nested within a container, such as a Card. This is showcased in the next section.
This is the content for Tab 1.
const [selectedTab, setSelectedTab] = useState(0);
return (
<Tabs
selectedTab={selectedTab}
onChange={setSelectedTab}
tabs={[
{
header: "Tab 1",
content: <Paragraph>This is the content for Tab 1.</Paragraph>,
},
{
header: "Tab 2",
content: <Paragraph>This is the content for Tab 2.</Paragraph>,
},
]}
/>
);
#Container-level
Here you seen an example of container-level tabs. That means the Tabs
component’s two parts, the tabs and their contents, are both nested within the same container. In this case, a Card component. This container could also have been a Modal or Side Panel.
A Card with container-level tabs should always feature a Card.Header
component. In other words, container-level tabs should not be used as a substitute for a Card.Header
.
Card header
This is the content for Tab 1.
const [selectedTab, setSelectedTab] = useState(0);
return (
<Card>
<Card.Header>Card header</Card.Header>
<Tabs
selectedTab={selectedTab}
onChange={setSelectedTab}
tabs={[
{
header: "Tab 1",
content: (
<Content>
<Paragraph>This is the content for Tab 1.</Paragraph>
</Content>
),
},
{
header: "Tab 2",
content: (
<Content>
<Paragraph>This is the content for Tab 2.</Paragraph>
</Content>
),
},
]}
/>
</Card>
);
#Page-level
Here you see an example of page-level tabs. That means the Tabs
component’s two parts, the tabs and their contents, are nested in different containers. The tabs are nested in a Card component by themselves. The tabs’ contents are nested in separate Cards
.
This configuration enables you to trigger the visibility of multiple Cards
on a page. Page-level tabs should only be used directly on a page — not in an overlay, such as a Modal or Side Panel.
Card A
This is the content for Card A belonging to Tab 1.
Card B
This is the content for Card B belonging to Tab 1.
const [selectedTab, setSelectedTab] = useState(0);
const [pageTabs, tabContent] = useTabSet({
selectedTab,
onChange: setSelectedTab,
tabs: [
{
header: "Tab 1",
content: (
<>
<Card>
<Card.Header>Card A</Card.Header>
<Content>
<Paragraph>This is the content for Card A belonging to Tab 1.</Paragraph>
</Content>
</Card>
<Card>
<Card.Header>Card B</Card.Header>
<Content>
<Paragraph>This is the content for Card B belonging to Tab 1.</Paragraph>
</Content>
</Card>
</>
),
},
{
header: "Tab 2",
content: (
<>
<Card>
<Card.Header>Card C</Card.Header>
<Content>
<Paragraph>This is the content for Card C belonging to Tab 2.</Paragraph>
</Content>
</Card>
<Card>
<Card.Header>Card D</Card.Header>
<Content>
<Paragraph>This is the content for Card D belonging to Tab 2.</Paragraph>
</Content>
</Card>
</>
),
},
],
});
return (
<>
<Card>{pageTabs}</Card>
{tabContent}
</>
);
#Mounted
The contents of a tab is by default unmounted when a different tab is selected. However, it's also possible to keep tab contents mounted . This is done by setting the keepTabsMounted
property to true
, as shown in the example below.
Card A
This Card belongs to Tab 1 and will remain mounted when you select Tab 2.
const [selectedTab, setSelectedTab] = useState(0);
const [pageTabs, tabContent] = useTabSet({
selectedTab,
keepTabsMounted: true,
onChange: setSelectedTab,
tabs: [
{
header: "Tab 1",
content: (
<>
<Card>
<Card.Header>Card A</Card.Header>
<Content>
<Paragraph>
This Card belongs to Tab 1 and will remain mounted when you select Tab 2.
</Paragraph>
</Content>
</Card>
</>
),
},
{
header: "Tab 2",
content: (
<>
<Card>
<Card.Header>Card B</Card.Header>
<Content>
<Paragraph>
This Card belongs to Tab 2 and will remain mounted when you select Tab 1.
</Paragraph>
</Content>
</Card>
</>
),
},
],
});
return (
<>
<Card>{pageTabs}</Card>
{tabContent}
</>
);
#Tabs with data-observe-keys
If you want to track the activity of the individual tabs, you can assign a data-observe-key
to each tab, as shown in the example below.
This is the content for Tab 1.
const [selectedTab, setSelectedTab] = useState(0);
return (
<Tabs
selectedTab={selectedTab}
onChange={setSelectedTab}
tabs={[
{
header: "Tab 1",
content: <Paragraph>This is the content for Tab 1.</Paragraph>,
"data-observe-key": "tab-1",
},
{
header: "Tab 2",
content: <Paragraph>This is the content for Tab 2.</Paragraph>,
"data-observe-key": "tab-2",
},
]}
/>
);
#Badges
Here you seen an example of how to add badges to tabs. Badges are used to indicate the status or category of a UI element. Place them to the right of tab labels and set their size
prop to small
.
Tasks
- Task 1
- Task 2
- Task 3
const [selectedTab, setSelectedTab] = useState(0);
return (
<Card>
<Card.Header>Tasks</Card.Header>
<Tabs
selectedTab={selectedTab}
onChange={setSelectedTab}
tabs={[
{
header: (
<>
To do
<Badge type="subtle" size="small" variant="light">
3
</Badge>
</>
),
content: (
<Content>
<Ul items={["Task 1", "Task 2", "Task 3"]} />
</Content>
),
},
{
header: (
<>
Doing
<Badge type="neutral" size="small" variant="light">
2
</Badge>
</>
),
content: (
<Content>
<Ul items={["Task 1", "Task 2"]} />
</Content>
),
},
{
header: (
<>
Done
<Badge type="positive" size="small" variant="light">
5
</Badge>
</>
),
content: (
<Content>
<Ul items={["Task 1", "Task 2", "Task 3", "Task 4", "Task 5"]} />
</Content>
),
},
]}
/>
</Card>
);
#Icons
Here you seen an example of how to add icons to tabs. The icons should improve scannability or clarify the meaning of the tab labels. They should also always be placed to the left of tab labels.
Issues
- Potential issue 1
- Potential issue 2
- Potential issue 3
- Potential issue 4
- Potential issue 5
const [selectedTab, setSelectedTab] = useState(0);
return (
<Card>
<Card.Header>Issues</Card.Header>
<Tabs
selectedTab={selectedTab}
onChange={setSelectedTab}
tabs={[
{
header: (
<>
<Icon>
<IconPotentialIssue />
</Icon>
Potential
</>
),
content: (
<Content>
<Ul
items={[
"Potential issue 1",
"Potential issue 2",
"Potential issue 3",
"Potential issue 4",
"Potential issue 5",
]}
/>
</Content>
),
},
{
header: (
<>
<Icon>
<IconResolvedIssue />
</Icon>
Resolved
</>
),
content: (
<Content>
<Ul
items={[
"Resolved issue 1",
"Resolved issue 2",
"Resolved issue 3",
"Resolved issue 4",
"Resolved issue 5",
]}
/>
</Content>
),
},
]}
/>
</Card>
);
#Properties
This is the content for Tab 1.
Property | Description | Defined | Value |
---|---|---|---|
tabsRequired | object[] List of Tabs | ||
selectedTabRequired | number Default selected tab | ||
onInitOptional | function Execute once tabs has been initialized | ||
onChangeOptional | function Executes once tab has changed | ||
onUnMountOptional | function Callback that calls when tabs are unmounted, typically for routing control | ||
keepTabsMountedOptional | boolean If true, the tabs will remain mounted after another tab is selected | ||
inStaticModeOptional | "disable" | "hide" | "show" Specifies how tabs look in the static mode. Defaults to `disable`. | ||
data-observe-keyOptional | string Unique string, used by external script e.g. for event tracking | ||
classNameOptional | string Custom className that's applied to the outermost element (only intended for special cases) | ||
styleOptional | object Style object to apply custom inline styles (only intended for special cases) |
#Guidelines
#Best practices
#Do not use when
#Accessibility
Explore detailed guidelines for this component: Accessibility Specifications
#Writing
#Notable Changes
#Version 0.0.x
- The
CardTabbed
andPageTabs
components have been removed. Instead, there's now just a single component:Tabs
. It can be configured to function as container-level or page-level tabs.