The strip that splits a settings panel into two or three questions instead of one long scroll. It is the strip and nothing else: what the tabs switch between stays in the panel's own markup, beside the state that decides it. The pill slides between equal columns, arrow keys both move and select, and a tab can carry a count of what has changed under it.
The import and the props worth knowing about, in one place.
import { InspectorTabs } from "@/components/beste/component/inspector-tabs";
// The panel owns its body, so the strip only has to say which one is showing
const [tab, setTab] = React.useState("design");
<InspectorTabs
value={tab}
onValueChange={setTab}
aria-label="Section settings"
tabs={[
{ value: "design", label: "Design" },
{ value: "content", label: "Content", badge: 2 }, // a count of what has changed
{ value: "seo", label: "SEO", disabled: !hasSeo },
]}
/>
{tab === "design" ? <DesignRows /> : null}
{tab === "content" ? <ContentRows /> : null}
// With a body of your own, point each tab at it so the two are tied together for
// anyone not looking at the screen
<InspectorTabs
value={tab}
onValueChange={setTab}
tabs={[
{ value: "design", label: "Design", controls: "design-rows" },
{ value: "content", label: "Content", controls: "content-rows" },
]}
/>
<div id="design-rows" role="tabpanel" hidden={tab !== "design"}>
<DesignRows />
</div>
// A switcher and nothing else, which panels want just as often. Give it an
// aria-label, since there is no visible text naming the set.
<InspectorTabs
aria-label="Direction"
size="sm" // "sm" | "default" | "lg"
tone="outline" // "muted" (default) | "outline" | "ghost"
value={direction}
onValueChange={setDirection}
tabs={[
{ value: "row", label: "Row", icon: MoveHorizontalIcon },
{ value: "column", label: "Column", icon: MoveVerticalIcon },
]}
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Left / Right | Move to the next tab and select it |
|---|---|
| Home / End | Jump to the first or last tab |
| Tab | Leaves the strip for whatever the panel puts after it |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | InspectorTab[] | — | The tabs, in the order they are shown. |
value | string | — | Controlled selection, by `value`. Pair it with `onValueChange`. |
defaultValue | string | — | Initial selection in uncontrolled mode. Falls back to the first tab. |
onValueChange | (value: string) => void | — | |
disabled | boolean | — | Block interaction and dim the strip. |
tone | "muted" | "outline" | "ghost" | "muted" | Surface treatment of the strip: filled (default), hairline outline, or bare. |
size | "sm" | "default" | "lg" | "default" | Strip height preset. |
className | string | — | |
aria-label | string | — | Accessible name for the strip. |