Accessible, controlled tab set. Tabs is the container; Tabs.Panel declares each tab (its button label and, optionally, its panel content). Tabs.PanelContent renders panel content outside the tab bar.
Use Tabs to switch between mutually exclusive views. It is fully controlled — you own the active tab via value / onChange. Declare tabs with Tabs.Panel; put content inside the panel, or leave the panel empty and render content elsewhere with Tabs.PanelContent.
There is no @uxf/form twin — Tabs is a navigation/content component.
import { Tabs } from "@uxf/ui/tabs";
import { useState } from "react";
function Example() {
const [activeTab, setActiveTab] = useState("tab-1");
return (
<Tabs onChange={setActiveTab} value={activeTab}>
<Tabs.Panel label="First" name="tab-1">
First panel
</Tabs.Panel>
<Tabs.Panel label="Second" name="tab-2">
Second panel
</Tabs.Panel>
</Tabs>
);
}
value / onChange are generic over the tab name type, so an enum or a union of string literals works directly.
Leave the panels empty and render each tab's content separately with Tabs.PanelContent:
<Tabs onChange={setActiveTab} value={activeTab}>
<Tabs.Panel label="Tab 1" name="tab-1" />
<Tabs.Panel label="Tab 2" name="tab-2" />
</Tabs>
<Tabs.PanelContent activeTab={activeTab} name="tab-1">
Content rendered elsewhere on the page
</Tabs.PanelContent>
<Tabs.PanelContent activeTab={activeTab} name="tab-2">
Content rendered elsewhere on the page
</Tabs.PanelContent>
Tabs| Prop | Type | Default | Description |
|---|---|---|---|
value |
TValue |
— | Required. name of the active tab. |
onChange |
(value: TValue) => void |
— | Required. Called with the newly selected tab's name. |
children |
ReactNode |
— | Required. Tabs.Panel elements. |
isVertical |
boolean |
false |
Vertical tab layout; also switches arrow-key navigation to Up/Down. |
variant |
TabsVariant |
"default" |
Visual style (see Variants & states). |
className |
string |
— | Class on the root. |
classNameButtonList |
string |
— | Class on the tab button list. |
Tabs.PanelDeclarative only — Tabs.Panel renders nothing itself; Tabs reads its props to build the tab buttons and panels.
| Prop | Type | Default | Description |
|---|---|---|---|
name |
string |
— | Required. Unique tab identifier, compared against value. |
label |
ReactNode | ((props: { isActive: boolean }) => ReactNode) |
— | Required. Tab button content, or a render function receiving the active state. |
children |
ReactNode |
— | Panel content. If no panel declares children, the panel area is not rendered (use Tabs.PanelContent). |
isDisabled |
boolean |
false |
Disable the tab; skipped in keyboard navigation. |
isHidden |
boolean |
false |
Hide the tab entirely. |
isAlwaysMounted |
boolean |
false |
Keep the panel mounted even while inactive. |
classNameButton |
string |
— | Class on the tab button. |
classNamePanel |
string |
— | Class on the panel. |
Tabs.PanelContent| Prop | Type | Default | Description |
|---|---|---|---|
name |
string |
— | Required. Tab identifier this content belongs to. |
activeTab |
string |
— | Required. Currently active tab (your value). |
children |
ReactNode |
— | Content shown when activeTab === name. |
shouldStayRendered |
boolean |
false |
Keep content mounted (hidden) when inactive. |
className |
string |
— | Class on the content wrapper. |
Built-in variant values (from theme.ts):
| Group | Values |
|---|---|
variant |
default, segmented |
TabsVariants is an open interface — a project can add its own values via module augmentation:
// tabs.d.ts
declare module "@uxf/ui/tabs/theme" {
interface TabsVariants {
pills: true;
}
}
Behaviour:
isVertical), skipping disabled and hidden tabs.Import the component stylesheet once in your global CSS:
@import url("@uxf/ui/css/tabs.css");
tabs.css defines its own --uxf-tabs-* CSS variables (spacing, colors, button styling), which you can override per app to theme the component.