Pho Design System

Tabs

Switches between peer views in the same context — Overview / Activity / Settings. Built on Base UI Tabs: the active tab renders as the inverted chip (photon.codes’ Tab), with an optional Indicator that slides between tabs and full arrow-key navigation.

Import

import { Tabs } from "@photon-ai/pho-ui/components/tabs";

Basic

Each Tabs.Tab and its Tabs.Panel share a value. The active tab is the inverted chip; drop a Tabs.Indicator in the list for a sliding highlight. Leave it uncontrolled with defaultValue.

A summary of your project — deployments, domains, and usage at a glance.
<Tabs.Root defaultValue="overview">
  <Tabs.List>
    <Tabs.Tab value="overview">Overview</Tabs.Tab>
    <Tabs.Tab value="activity">Activity</Tabs.Tab>
    <Tabs.Indicator />
  </Tabs.List>
  <Tabs.Panel value="overview">…</Tabs.Panel>
  <Tabs.Panel value="activity">…</Tabs.Panel>
</Tabs.Root>

Controlled

Pass value and onValueChange to own the active tab in your own state — for deep-linking a tab to the URL, syncing two tab bars, or driving selection from elsewhere in the UI.

A summary of your project — deployments, domains, and usage at a glance.
const [value, setValue] = useState("overview");

<Tabs.Root value={value} onValueChange={setValue}>
  <Tabs.List>
    <Tabs.Tab value="overview">Overview</Tabs.Tab>
    <Tabs.Tab value="activity">Activity</Tabs.Tab>
    <Tabs.Indicator />
  </Tabs.List>
  <Tabs.Panel value="overview">…</Tabs.Panel>
  <Tabs.Panel value="activity">…</Tabs.Panel>
</Tabs.Root>;

Anatomy

Props

Each part forwards to its Base UI counterpart and accepts that element’s native props plus className. The load-bearing props:

Tabs.Root

Tabs.List

Tabs.Tab

Tabs.Panel

Accessibility

Tabs.List is a role="tablist", each Tabs.Tab a role="tab" carrying aria-selected and aria-controls for its panel, and each Tabs.Panel a focusable role="tabpanel" labelled by its tab. A roving tabindex keeps only the active tab in the page’s tab order.

Keyboard:

Focus is shown with the pho-brand focus-visible ring on both tabs and panels. There is no live region — selection is conveyed through aria-selected.

Best practices