Switch between views of the same context — a record's sections, status filters, a List/Grid switch. Three variants, vertical orientation, counts, scrolling overflow, and route-based link tabs.
- Today, 09:42Call with Laura Callahan — renewal scope agreed
- YesterdayProposal v3 sent to procurement
- Nov 4Meeting: quarterly business review
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@vamos-ui/react";
<Tabs defaultValue="overview">
<TabsList aria-label="Contact">
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="deals" count={4}>Deals</TabsTrigger>
</TabsList>
<TabsContent value="overview">…</TabsContent>
<TabsContent value="deals">…</TabsContent>
</Tabs>Inactive panels unmount, so state inside them resets — lift it up or use forceMount.
A "More ▾" overflow menu is planned; today overflow scrolls.
Examples
Variants
underline for pages and records, pill for status filters, segmented for a 2–4 option view switch.
With counts
count is locale-formatted and capped at 99+. It is part of the accessible name ("Draft, 12"). The selected pill tints its count with the accent.
Segmented view switch
Controlled with value / onValueChange. For a value picker inside a form use a radio group instead — tabs switch views.
Media library
- Hero — autumn campaign.jpg2400 × 1350 · 1.8 MB
- Team offsite.jpg1600 × 1067 · 940 KB
- Store front, Kadıköy.jpg1920 × 1280 · 1.2 MB
- Product flat lay.jpg2000 × 2000 · 2.1 MB
Vertical (settings)
orientation="vertical" moves the indicator to the start edge; ↑ ↓ move between tabs.
Two-factor authentication
Enabled with an authenticator app since March 2026. 6 recovery codes left.
Synced with the URL
URL state stays in your app. Read ?tab= on load and replace it on change.
?tab=overview — reload and the tab is kept.Link tabs (routes)
TabsLinkList is a nav of router links with aria-current="page" — not the Tabs pattern. The active tab comes from VamosProvider currentPath; use exact on the index route.
Overflow
Tabs that don't fit scroll horizontally with edge fades, and the selected tab is scrolled into view.
API
Tabs
| Prop | Type | Default |
|---|---|---|
valueControlled selected tab. | string | — |
defaultValueInitial tab when uncontrolled. | string | — |
onValueChangeCalled when the selection changes. | (value: string) => void | — |
orientationVertical puts the list beside the panels and switches arrow keys to ↑ ↓. | "horizontal" | "vertical" | "horizontal" |
activationModemanual: arrows only move focus; Enter / Space selects (heavy panels). | "automatic" | "manual" | "automatic" |
dirReading direction; defaults to the LocaleProvider direction. | "ltr" | "rtl" | — |
TabsList
| Prop | Type | Default |
|---|---|---|
variantVisual style. | "underline" | "pill" | "segmented" | "underline" |
sizeTrigger height and text size; segmented follows --control-h. | "sm" | "md" | "md" |
fillEqual-width tabs that fill the row. | boolean | false |
overflowHorizontal lists scroll with edge fades and keep the selected tab in view. | "scroll" | "none" | "scroll" |
loopArrow keys wrap around. | boolean | true |
TabsTrigger
| Prop | Type | Default |
|---|---|---|
valueRequired. Matches a TabsContent. | string | — |
iconLeading icon. | ReactNode | — |
countTrailing count badge (locale-formatted, 99+). | number | — |
badgeToneTone of the count badge (selected pill / segmented tabs use accent). | BadgeProps["tone"] | "neutral" |
disabledSkipped by the keyboard. | boolean | false |
TabsContent
| Prop | Type | Default |
|---|---|---|
valueRequired. The tab this panel belongs to. | string | — |
forceMountKeep the panel mounted while inactive (inactive panels unmount by default). | true | — |
TabsLinkList / TabsLink
| Prop | Type | Default |
|---|---|---|
aria-labelTabsLinkList: name of the nav landmark. | string | — |
variant · size · fill · orientation · overflowTabsLinkList: same as TabsList. | — | — |
hrefTabsLink: target; rendered with the app's router Link. | string | — |
exactTabsLink: active only on this exact path (index routes). | boolean | false |
activeTabsLink: force the active state instead of deriving it from currentPath. | boolean | — |
icon · count · badgeTone · disabledTabsLink: same as TabsTrigger. | — | — |