Segmented (default)
Underline
import { Tabs } from "@cloudflare/kumo";
export function TabsDefaultDemo() {
return (
<div className="flex flex-col gap-6">
<div>
<p className="mb-2 text-sm text-kumo-subtle">Segmented (default)</p>
<Tabs
variant="segmented"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
</div>
<div>
<p className="mb-2 text-sm text-kumo-subtle">Underline</p>
<Tabs
variant="underline"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
</div>
</div>
);
} Installation
Barrel
import { Tabs } from "@cloudflare/kumo";Granular
import { Tabs } from "@cloudflare/kumo/components/tabs"; Usage
import { Tabs } from "@cloudflare/kumo";
export default function Example() {
return (
<Tabs
tabs={[
{ value: "overview", label: "Overview" },
{ value: "settings", label: "Settings" },
]}
selectedValue="overview"
/>
);
} Examples
Variants
Segmented (Default)
A pill-shaped indicator slides between tabs on a subtle background.
import { Tabs } from "@cloudflare/kumo";
export function TabsSegmentedDemo() {
return (
<Tabs
variant="segmented"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
);
} Underline
A bottom border with a primary-colored indicator. The active tab has bolder text for emphasis.
import { Tabs } from "@cloudflare/kumo";
export function TabsUnderlineDemo() {
return (
<Tabs
variant="underline"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
);
} Controlled
Use the value and onValueChange props for controlled state.
Active tab: tab1
import { useState } from "react";
import { Tabs } from "@cloudflare/kumo";
export function TabsControlledDemo() {
const [activeTab, setActiveTab] = useState("tab1");
return (
<div className="space-y-4">
<Tabs
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
value={activeTab}
onValueChange={setActiveTab}
/>
<p className="text-sm text-kumo-subtle">
Active tab: <code className="text-sm">{activeTab}</code>
</p>
</div>
);
} Many Tabs
Tabs automatically scroll horizontally when there are many items.
import { Tabs } from "@cloudflare/kumo";
export function TabsManyDemo() {
return (
<Tabs
tabs={[
{ value: "overview", label: "Overview" },
{ value: "analytics", label: "Analytics" },
{ value: "reports", label: "Reports" },
{ value: "notifications", label: "Notifications" },
{ value: "settings", label: "Settings" },
{ value: "billing", label: "Billing" },
]}
selectedValue="overview"
/>
);
} API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| tabs | TabsItem[] | - | Array of tab items to render. |
| value | string | - | Controlled value. When set, component becomes controlled. |
| selectedValue | string | - | Default selected value for uncontrolled mode. Ignored when `value` is set. |
| activateOnFocus | boolean | - | When `true`, tabs are activated immediately upon receiving focus via arrow keys. When `false` (default), tabs receive focus but require Enter/Space to activate. |
| className | string | - | Additional CSS classes for the root element. |
| listClassName | string | - | Additional CSS classes for the tab list element. |
| indicatorClassName | string | - | Additional CSS classes for the indicator element. |
| variant | "segmented" | "underline" | "segmented" | Tab style. - `"segmented"` — Pill-shaped indicator on a filled track - `"underline"` — Underline indicator below tab text |
| onValueChange | (value: string) => void | - | Callback when active tab changes |
TabsItem
| Property | Type | Required |
|---|---|---|
| value | string | Yes |
| label | ReactNode | Yes |
| className | string | No |