Content
- One or two words, sentence case. A count may follow in a Tag.
Underline tabs that switch between views of one page.
import { … } from "@brdgapp/ui/components/tabs"Tabs switch between views of the same thing, such as an organization's People, Intros and Connectors. The selected tab is underlined in dark ink. The usual mistake is using tabs to move between different pages of the app: that's navigation, not tabs.
Sentence case
Buttons, titles, headings, tabs, labels and statuses use sentence case: only the first word and names get a capital. "Make intro", "Intro forwarded", "Stop sharing".
Tab list. A row with a 1px baseline; 24px between tabs. Scrolls sideways if it doesn't fit. If the page already draws the line under the row, pass shadow-none -mb-px so the tabs sit on that line.
Tab. 14px Bold, 0.4px letter spacing. Selected: dark ink with a 2px underline. Others: muted.
Panel. Optional. The content for each tab.
Try the arrow keys.
| Rest | Hover | Focus | Disabled | |
|---|---|---|---|---|
| Not selected | ||||
| Selected |
| State | What happens |
|---|---|
| Selected | --text-primary with a 2px underline. |
| Rest | --text-muted. |
| Hover | --text-body. |
| Focus visible | 2px blue ring. |
| Disabled | 30% opacity; arrow keys skip it. |
tablist, each tab a tab, each panel a tabpanel, all linked.<Tabs value onValueChange>.onValueChange to swap a view yourself.Do
Use short nouns: People, Intros.Don't
Write sentences or verbs in tabs.| Keys | Action |
|---|---|
| ←→ | Move focus between tabs. The view doesn't change yet, so a tab that loads data isn't fetched on every key press. |
| EnterSpace | Open the focused tab. |
| HomeEnd | First or last tab. |
| Tab | Leaves the list for the panel. |
Tabs
The group. Owns the selected value. Extends Base UI Tabs.Root.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | The selected tab. |
onValueChange | (value) => void | — | Called when the selection changes. |
defaultValue | string | — | Starting tab, when you don't control it. |
TabList
The row of tabs. Extends Base UI Tabs.List.
| Prop | Type | Default | Description |
|---|
Tab
One tab. Extends Base UI Tabs.Tab.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Which tab this is. |
TabPanel
The content for one tab. Extends Base UI Tabs.Panel.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Which tab it belongs to. |
What it's built from and where it's used, read from the code. When you change it, check these too.
Where the code still differs from the system. Follow the system, not the gap.
<Tab active> becomes <Tab value> inside <Tabs value>. The six Bridge OS call sites change when they move to the package.components.md → TabList / Tab; DESIGN.md → Navigation Tabs; src/components/ui/tabs.tsx.