Segmented (default)
Underline
import { Tabs } from "@photon-ai/kumo-solid";
export function TabsDefaultDemo() {
return (
<div class="flex flex-col gap-6">
<div>
<p class="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 class="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 "@photon-ai/kumo-solid";Granular
import { Tabs } from "@photon-ai/kumo-solid/components/tabs";Usage
import { Tabs } from "@photon-ai/kumo-solid";
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 "@photon-ai/kumo-solid";
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 "@photon-ai/kumo-solid";
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"
/>
);
}Small Size
Use size="sm" for a compact tab bar that matches Input size="sm" height (h-6.5 / 26px).
Useful inside toolbars and filter rows.
Segmented sm
Underline sm
import { Tabs } from "@photon-ai/kumo-solid";
export function TabsSmDemo() {
return (
<div class="flex flex-col gap-6">
<div>
<p class="mb-2 text-sm text-kumo-subtle">Segmented sm</p>
<Tabs
variant="segmented"
size="sm"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
</div>
<div>
<p class="mb-2 text-sm text-kumo-subtle">Underline sm</p>
<Tabs
variant="underline"
size="sm"
tabs={[
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
]}
selectedValue="tab1"
/>
</div>
</div>
);
}Controlled
Use the value and onValueChange props for controlled state.
Active tab: tab1
import { createSignal } from "solid-js";
import { Tabs } from "@photon-ai/kumo-solid";
export function TabsControlledDemo() {
const [activeTab, setActiveTab] = createSignal("tab1");
return (
<div class="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 class="text-sm text-kumo-subtle">
Active tab: <code class="text-sm">{activeTab()}</code>
</p>
</div>
);
}Many Tabs
Tabs automatically scroll horizontally when there are many items.
import { Tabs } from "@photon-ai/kumo-solid";
export function TabsManyDemo() {
return (
<div class="w-full max-w-md">
<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" },
{ value: "security", label: "Security" },
{ value: "integrations", label: "Integrations" },
]}
selectedValue="overview"
/>
</div>
);
}Horizontal Overflow
When tabs overflow their container, scroll buttons appear at the clipped edge. Use them, horizontal scrolling, or mouse drag to reveal off-screen tabs.
import { Tabs } from "@photon-ai/kumo-solid";
export function TabsOverflowDemo() {
return (
<div class="w-full max-w-xs">
<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" },
{ value: "security", label: "Security" },
{ value: "integrations", label: "Integrations" },
]}
selectedValue="overview"
/>
</div>
);
}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. |
| labels | TabsLabels | - | Labels for internationalization of aria-labels. All labels have English defaults. |
| variant | "segmented" | "underline" | "segmented" | Tab style. - `"segmented"` — Pill-shaped indicator on a filled track - `"underline"` — Underline indicator below tab text |
| size | "base" | "sm" | "base" | Tab size. - `"base"` — Default size (h-9, text-base) - `"sm"` — Compact size (h-6.5, text-xs) — matches Input size="sm" |
| onValueChange | (value: string) => void | - | Callback when active tab changes |
TabsItem
| Property | Type | Required |
|---|---|---|
| value | string | Yes |
| label | JSX.Element | Yes |
| className | string | No |