Tabs
Tabs switch between views that share one space. Each Tab has a title and an optional panel.
Usage#
import { Tab, TabPanel, Tabs } from "@clawscale/react";<Tabs id="dataset-tabs">
<Tab id="preview" title="Preview" panel={<PreviewPanel />} />
<Tab id="schema" title="Schema" panel={<SchemaPanel />} />
</Tabs>Tabs and every Tab need an id. The ids build the ARIA attributes, so keep them unique on the page. Other children render in the tab list in order. Insert a TabsExpander to push the children after it to the end.
Examples#
Basic#
Tabs manage their own selection. defaultSelectedTabId sets the first selected tab. disabled turns a tab off.
1,284 runs in the last 90 days. 99.2% succeeded.
import { Tab, Tabs } from "@clawscale/react";
export default function TabsBasic() {
return (
<Tabs id="pipeline-tabs" defaultSelectedTabId="runs">
<Tab id="overview" title="Overview" panel={<p>ingest_orders loads raw orders from Kafka every hour.</p>} />
<Tab id="runs" title="Runs" panel={<p>1,284 runs in the last 90 days. 99.2% succeeded.</p>} />
<Tab id="lineage" title="Lineage" panel={<p>Reads raw.orders. Writes curated.orders_daily.</p>} />
<Tab id="settings" title="Settings" disabled />
</Tabs>
);
}Tags on tabs#
tagContent renders a minimal tag after the title, for a count or a status. tagProps passes other props to the tag.
order_id, amount, region and 21 more.
import { Tab, Tabs } from "@clawscale/react";
export default function TabsTags() {
return (
<Tabs id="dataset-tabs">
<Tab id="columns" title="Columns" tagContent={24} panel={<p>order_id, amount, region and 21 more.</p>} />
<Tab id="partitions" title="Partitions" tagContent="1.2K" panel={<p>One partition per day since 2023.</p>} />
<Tab id="alerts" title="Alerts" tagContent={3} panel={<p>3 open alerts on freshness and row count.</p>} />
</Tabs>
);
}Vertical#
vertical stacks the tab list on the left and shows the panel on the right.
Workspace name, time zone and default region.
import { Tab, Tabs } from "@clawscale/react";
export default function TabsVertical() {
return (
<Tabs id="workspace-tabs" vertical>
<Tab id="general" title="General" panel={<p>Workspace name, time zone and default region.</p>} />
<Tab id="members" title="Members" panel={<p>42 members in 5 groups.</p>} />
<Tab id="connections" title="Connections" panel={<p>Kafka, Postgres and S3 sources.</p>} />
<Tab id="billing" title="Billing" panel={<p>1,820 compute hours this month.</p>} />
</Tabs>
);
}Fill#
fill stretches the tab list to the height of its parent, so the indicator sits on the bottom edge of a Navbar. Render the panels elsewhere. fill has no effect on vertical tabs.
import { Navbar, NavbarDivider, NavbarGroup, NavbarHeading, Tab, type TabId, TabPanel, Tabs } from "@clawscale/react";
import { useState } from "react";
const panels: Record<string, string> = {
preview: "First 100 rows of orders_daily.",
schema: "24 columns. Partitioned by order_date.",
lineage: "Built from raw.orders and raw.customers.",
history: "Last refreshed 12 minutes ago.",
};
export default function TabsFill() {
const [tab, setTab] = useState<TabId>("preview");
return (
<div style={{ width: "100%" }}>
<Navbar>
<NavbarGroup>
<NavbarHeading>orders_daily</NavbarHeading>
<NavbarDivider />
<Tabs id="dataset-nav" fill selectedTabId={tab} onChange={setTab}>
<Tab id="preview" title="Preview" />
<Tab id="schema" title="Schema" />
<Tab id="lineage" title="Lineage" />
<Tab id="history" title="History" />
</Tabs>
</NavbarGroup>
</Navbar>
<TabPanel id={tab} parentId="dataset-nav" selectedTabId={tab} panel={<p>{panels[tab]}</p>} />
</div>
);
}Controlled#
Pass selectedTabId and onChange to control the selection, for example from a button or the URL.
Run 1283 of refresh_revenue failed after 1 min 48 s.
import { Button, Tab, type TabId, Tabs } from "@clawscale/react";
import { useState } from "react";
export default function TabsControlled() {
const [tab, setTab] = useState<TabId>("summary");
return (
<>
<Tabs id="run-tabs" selectedTabId={tab} onChange={setTab}>
<Tab id="summary" title="Summary" panel={<p>Run 1283 of refresh_revenue failed after 1 min 48 s.</p>} />
<Tab id="logs" title="Logs" panel={<p>06:17:11 ERROR column amount has 12 null values</p>} />
<Tab id="config" title="Config" panel={<p>Source raw.orders. Target curated.revenue_by_region.</p>} />
</Tabs>
<div>
<Button disabled={tab === "logs"} icon="console" text="Show the error" onClick={() => setTab("logs")} />
</div>
</>
);
}Tab panel#
To show the content elsewhere in the DOM, leave out panel and render a TabPanel yourself. It sets the ARIA attributes that link it to its tab. Pass the id of the Tabs as parentId.
First 100 of 3.4M rows.
import { Card, Tab, type TabId, TabPanel, Tabs } from "@clawscale/react";
import { useState } from "react";
const PANELS: Record<string, string> = {
preview: "First 100 of 3.4M rows.",
schema: "24 columns. Primary key order_id.",
lineage: "Upstream raw.orders. Downstream finance.revenue.",
};
export default function TabsTabPanel() {
const [tab, setTab] = useState<TabId>("preview");
return (
<>
<Tabs id="dataset-view" selectedTabId={tab} onChange={setTab}>
<Tab id="preview" title="Preview" />
<Tab id="schema" title="Schema" />
<Tab id="lineage" title="Lineage" />
</Tabs>
<Card>
<TabPanel id={tab} selectedTabId={tab} parentId="dataset-view" panel={<p>{PANELS[tab]}</p>} />
</Card>
</>
);
}Props interface#
interface TabsProps extends Props@clawscale/react| Props | Description |
|---|---|
animate | boolean = trueWhether the selected tab indicator should animate its movement. |
children | React.ReactNodeTab elements. |
className | stringA space-delimited list of class names to pass along to a child element. Inherited from Props |
defaultSelectedTabId | TabId = first tabInitial selected tab id, for uncontrolled usage. Note that this prop refers only to <Tab> children; other types of elements are ignored. |
fill | boolean = falseWhether to make the tabs list fill the height of its parent. |
idrequired | TabIdUnique identifier for this Tabs container. This will be combined with the id of each Tab child to generate ARIA accessibility attributes. IDs are required and should be unique on the page to support server-side rendering. |
largedeprecated | boolean = falseIf set to true, the tab titles will display with larger styling. This will apply large styles only to the tabs at this level, not to nested tabs.use size="large" instead |
onChange | (newTabId: TabId, prevTabId: TabId | undefined, event: MouseEvent<HTMLElement, MouseEvent>): voidA callback function that is invoked when a tab in the tab list is clicked. |
renderActiveTabPanelOnly | boolean = falseWhether inactive tab panels should be removed from the DOM and unmounted in React. This can be a performance enhancement when rendering many complex panels, but requires careful support for unmounting and remounting. |
selectedTabId | TabIdSelected tab id, for controlled usage. Providing this prop will put the component in controlled mode. Unknown ids will result in empty selection (no errors). |
size | NonSmallSize = "medium"The size of the tab titles. |
vertical | boolean = falseWhether to show tabs stacked vertically on the left side. |
interface TabProps extends Props, Omit<HTMLDivProps, "id" | "title" | "onClick">@clawscale/react| Props | Description |
|---|---|
children | React.ReactNodeContent of tab title, rendered in a list above the active panel. Can also be set via the title prop. |
className | stringA space-delimited list of class names to pass along to a child element. Inherited from Props |
disabled | boolean = falseWhether the tab is disabled. |
icon | IconName | MaybeElementName of a Blueprint UI icon (or an icon element) to render before the children. |
idrequired | TabIdUnique identifier used to control which tab is selected and to generate ARIA attributes for accessibility. |
panel | React.JSX.Element | ((props: TabIdProps) => React.JSX.Element)Panel content, rendered by the parent Tabs when this tab is active. If omitted, no panel will be rendered for this tab. Can either be an element or a renderer. |
panelClassName | stringSpace-delimited string of class names applied to tab panel container. |
tagContent | TagProps["children"]Content to render inside a <Tag> after the children. The tag is minimal by default; it can be further modified by using tagProps. |
tagProps | Omit<TagProps, "children">Props to customize the <Tag> rendered after the children. This has no effect if tagContent is undefined. |
title | React.ReactNodeContent of tab title element, rendered in a list above the active panel. Can also be set via React children. |
interface TabPanelProps extends Pick<TabProps, "className" | "id" | "panel">, Pick<TabsProps, "renderActiveTabPanelOnly" | "selectedTabId">, Pick<TabTitleProps, "parentId">@clawscale/react| Props | Description |
|---|---|
className | stringA space-delimited list of class names to pass along to a child element. Inherited from Props |
idrequired | TabIdUnique identifier used to control which tab is selected and to generate ARIA attributes for accessibility. Inherited from TabProps |
panel | React.JSX.Element | ((props: TabIdProps) => React.JSX.Element)Panel content, rendered by the parent Inherited from Tabs when this tab is active. If omitted, no panel will be rendered for this tab. Can either be an element or a renderer.TabProps |
parentIdrequired | TabIdID of the parent Inherited from Tabs to which this tab belongs. Used to generate ID for ARIA attributes.TabTitleProps |
renderActiveTabPanelOnly | boolean = falseWhether inactive tab panels should be removed from the DOM and unmounted in React. This can be a performance enhancement when rendering many complex panels, but requires careful support for unmounting and remounting. Inherited from TabsProps |
selectedTabIdrequired | TabId | undefinedUsed for setting visibility. This TabPanel will be visibile when selectedTabId === id, with proper accessibility attributes set. |