Tabs
A set of layered sections that show one panel at a time.
Show codeHide code
Installation
import { Tabs, TabsList, Tab, TabsPanel } from "@makeplane/propel/components/tabs";Usage
import { Icon } from "@makeplane/propel/components/icon";
import { Tab, Tabs, TabsList, TabsPanel } from "@makeplane/propel/components/tabs";
import { ActivityOutline, GridLayoutOutline, SettingsOutline } from "@makeplane/propel/icons";
import * as React from "react";
const TAB_ITEMS = [
{
value: "overview",
label: "Overview",
icon: <Icon icon={GridLayoutOutline} />,
panel: "A high-level summary of the project.",
},
{
value: "activity",
label: "Activity",
icon: <Icon icon={ActivityOutline} />,
panel: "The latest activity feed.",
},
{
value: "settings",
label: "Settings",
icon: <Icon icon={SettingsOutline} />,
panel: "Configuration and preferences.",
},
];
export default function BasicDemo() {
const [value, setValue] = React.useState("overview");
return (
<div className="w-96">
<Tabs variant="contained" value={value} onValueChange={setValue}>
<TabsList>
{TAB_ITEMS.map((tab) => (
<Tab key={tab.value} value={tab.value} icon={tab.icon} label={tab.label} />
))}
</TabsList>
{TAB_ITEMS.map((tab) => (
<TabsPanel key={tab.value} value={tab.value}>
{tab.panel}
</TabsPanel>
))}
</Tabs>
</div>
);
}Examples
Underline
The underline variant keeps the tabs flat and slides a bar under the active one, in contrast to the raised contained pill.
Show codeHide code
Full width
stretch="full" makes the tab row fill its container, splitting it into equal-width tabs — most visible on the contained segmented-control look.
Show codeHide code
Fill a bounded layout
layout="fill" makes the Tabs root and active panel consume a bounded parent’s available height. Keep the parent in a bounded flex layout and put scrolling on the panel content. The default layout="content" preserves content-sized tabs.
Show codeHide code
Disabled
Show codeHide code
Overflow
TabsList composes a horizontal ScrollArea: when the tabs are wider than their container the row scrolls instead of overflowing, its overlay scrollbar fading in on hover or scroll. Keyboard navigation still reaches every tab — the focused tab is kept in view.
Navigation tab
Tab composes a custom element or function render target through its styled element, preserving Propel styling and Base UI behavior. When it renders as a navigation link, set nativeButton={false} so Base UI does not apply native-button-only attributes to the anchor. Tabs and TabsPanel keep their standard rendered elements.
Show codeHide code
API Reference
Tabs
The ready-made tab set: grafts the Base UI Tabs.Root behavior onto the styled elements/tabs
root and shares its variant/stretch with the TabsList/Tabs and its layout with the
TabsPanels inside via context, so you don't repeat them.
TabsList
The ready-made tab strip: grafts the Base UI ScrollArea.Root onto the styled
TabsListScrollArea frame, then grafts the Base UI Tabs.List behavior onto the styled
TabsList (taking the set's variant/stretch from context) rendered as the scroll viewport,
plus a horizontal scrollbar so a long row of tabs scrolls, and renders the active-tab underline
TabsIndicator for the underline variant.
Tab
The ready-made tab button: grafts the Base UI Tabs.Tab behavior onto the styled elements/tabs
tab (taking the set's variant/stretch from context, so you don't pass them) and lays out an
optional icon with the label. The underline variant additionally renders the sliding bar
track beneath the label. A consumer render target is composed through the styled tab,
preserving Propel's classes; render callbacks receive the original Base UI tab state.
TabsPanel
The ready-made tab panel: grafts the Base UI Tabs.Panel behavior (shown when the Tab of the
matching value is active) onto the styled elements/tabs panel and applies the set's height
layout from context.