Clawscale

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.

orders_daily

First 100 rows of orders_daily.

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
PropsDescription
animate
boolean = true
Whether the selected tab indicator should animate its movement.
children
React.ReactNode
Tab elements.
className
string
A space-delimited list of class names to pass along to a child element.
Inherited from Props
defaultSelectedTabId
TabId = first tab
Initial selected tab id, for uncontrolled usage. Note that this prop refers only to <Tab> children; other types of elements are ignored.
fill
boolean = false
Whether to make the tabs list fill the height of its parent.
idrequired
TabId
Unique 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 = false
If 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>): void
A callback function that is invoked when a tab in the tab list is clicked.
renderActiveTabPanelOnly
boolean = false
Whether 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
TabId
Selected 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 = false
Whether to show tabs stacked vertically on the left side.
interface TabProps extends Props, Omit<HTMLDivProps, "id" | "title" | "onClick">@clawscale/react
PropsDescription
children
React.ReactNode
Content of tab title, rendered in a list above the active panel. Can also be set via the title prop.
className
string
A space-delimited list of class names to pass along to a child element.
Inherited from Props
disabled
boolean = false
Whether the tab is disabled.
icon
IconName | MaybeElement
Name of a Blueprint UI icon (or an icon element) to render before the children.
idrequired
TabId
Unique 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
string
Space-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.ReactNode
Content 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
PropsDescription
className
string
A space-delimited list of class names to pass along to a child element.
Inherited from Props
idrequired
TabId
Unique 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 Tabs when this tab is active. If omitted, no panel will be rendered for this tab. Can either be an element or a renderer.
Inherited from TabProps
parentIdrequired
TabId
ID of the parent Tabs to which this tab belongs. Used to generate ID for ARIA attributes.
Inherited from TabTitleProps
renderActiveTabPanelOnly
boolean = false
Whether 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 | undefined
Used for setting visibility. This TabPanel will be visibile when selectedTabId === id, with proper accessibility attributes set.