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

PropTypeDefaultDescription
tabsTabsItem[]-Array of tab items to render.
valuestring-Controlled value. When set, component becomes controlled.
selectedValuestring-Default selected value for uncontrolled mode. Ignored when `value` is set.
activateOnFocusboolean-When `true`, tabs are activated immediately upon receiving focus via arrow keys. When `false` (default), tabs receive focus but require Enter/Space to activate.
classNamestring-Additional CSS classes for the root element.
listClassNamestring-Additional CSS classes for the tab list element.
indicatorClassNamestring-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

PropertyTypeRequired
valuestringYes
labelReactNodeYes
classNamestringNo