Tabs
Tabbed interface for switching between grouped content panels.
pnpm dlx @glinui/cli@latest add tabsLumen web app
Production, deployed 12 minutes ago
Installation
pnpm dlx @glinui/cli@latest add tabsPrefer the package?
Usage
Underline with icons
The underline look with icons, a count badge and a disabled tab.
"use client"
import { Receipt, ShieldCheck, UsersThree } from "@phosphor-icons/react"import { Badge, Tabs, TabsContent, TabsList, TabsTrigger, Text} from "@glinui/ui"
export function TabsUnderlineExample() { return ( <div className="mx-auto w-full max-w-xl"> <Tabs defaultValue="members"> <TabsList variant="underline" className="w-full justify-start overflow-x-auto"> <TabsTrigger value="members" className="gap-1.5"><UsersThree aria-hidden="true" />Members</TabsTrigger> <TabsTrigger value="roles" className="gap-1.5"><ShieldCheck aria-hidden="true" />Roles</TabsTrigger> <TabsTrigger value="invoices" className="gap-1.5"><Receipt aria-hidden="true" />Invoices <Badge size="sm">3</Badge></TabsTrigger> <TabsTrigger value="locked" disabled>Audit log</TabsTrigger> </TabsList> <TabsContent value="members"><Text size="sm" className="pt-4 text-[var(--color-muted)]">12 members across 3 teams.</Text></TabsContent> <TabsContent value="roles"><Text size="sm" className="pt-4 text-[var(--color-muted)]">Owner, admin, editor and viewer roles.</Text></TabsContent> <TabsContent value="invoices"><Text size="sm" className="pt-4 text-[var(--color-muted)]">3 invoices are waiting for payment.</Text></TabsContent> </Tabs> </div> )}Variants
Set variant once on Tabs and the list, triggers and panels inherit it. glinr is the raised pill track, underline slides an accent bar with transform only.
import { Tabs, TabsList, TabsTrigger } from "@glinui/ui"
export function Demo() { return ( <div className="grid gap-4 md:grid-cols-2"> <Tabs defaultValue="a" variant="glinr"> <TabsList> <TabsTrigger value="a">glinr</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> <Tabs defaultValue="a" variant="solid"> <TabsList> <TabsTrigger value="a">solid</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> <Tabs defaultValue="a" variant="plain"> <TabsList> <TabsTrigger value="a">plain</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> <Tabs defaultValue="a" variant="soft"> <TabsList> <TabsTrigger value="a">soft</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> <Tabs defaultValue="a" variant="outline"> <TabsList> <TabsTrigger value="a">outline</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> <Tabs defaultValue="a" variant="underline"> <TabsList> <TabsTrigger value="a">underline</TabsTrigger> <TabsTrigger value="b">Two</TabsTrigger> <TabsTrigger value="c">Three</TabsTrigger> </TabsList> </Tabs> </div> )}Glass (opt-in)
Glass is opt-in and needs a backdrop behind it: pick Photo or Vivid in the stage backdrop switcher.
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@glinui/ui"
export function Demo() { return ( <Tabs defaultValue="first" variant="glass"> <TabsList> <TabsTrigger value="first">First</TabsTrigger> <TabsTrigger value="second">Second</TabsTrigger> </TabsList> <TabsContent value="first">Glass tab content.</TabsContent> <TabsContent value="second">Second panel.</TabsContent> </Tabs> )}Liquid + Matte Variants
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@glinui/ui"
export function Demo() { return ( <div className="grid gap-4 md:grid-cols-2"> <Tabs defaultValue="liquid-1"> <TabsList variant="liquid"> <TabsTrigger value="liquid-1" variant="liquid">Liquid A</TabsTrigger> <TabsTrigger value="liquid-2" variant="liquid">Liquid B</TabsTrigger> </TabsList> <TabsContent value="liquid-1" variant="liquid">Liquid tab surface.</TabsContent> <TabsContent value="liquid-2" variant="liquid">Second liquid panel.</TabsContent> </Tabs> <Tabs defaultValue="matte-1"> <TabsList variant="matte"> <TabsTrigger value="matte-1" variant="matte">Matte A</TabsTrigger> <TabsTrigger value="matte-2" variant="matte">Matte B</TabsTrigger> </TabsList> <TabsContent value="matte-1" variant="matte">Matte tab surface.</TabsContent> <TabsContent value="matte-2" variant="matte">Second matte panel.</TabsContent> </Tabs> </div> )}Keys variant
Raised pill track where the selected tab is a white gradient key. Pass variant to list, triggers and content.
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@glinui/ui"
export function Demo() {
return (
<Tabs defaultValue="a">
<TabsList variant="keys" aria-label="Plan">
<TabsTrigger variant="keys" value="a">Cloud</TabsTrigger>
<TabsTrigger variant="keys" value="b">Self-hosted</TabsTrigger>
</TabsList>
<TabsContent variant="keys" value="a">Cloud panel</TabsContent>
<TabsContent variant="keys" value="b">Self-hosted panel</TabsContent>
</Tabs>
)
}Accessibility
- Built on Radix Tabs with full WAI-ARIA.
- Content is associated via `aria-controls`.
- Use clear trigger labels for each panel.
Keyboard Interactions
| Key | Action |
|---|---|
| Arrow Left / Right | Navigate between tab triggers. |
| Enter / Space | Select the focused tab. |
ARIA Attributes
- `role="tablist"` on list
- `role="tab"` on triggers
- `role="tabpanel"` on content
- `aria-selected`
- `aria-controls`
Reduced Motion
Active indicator transitions respect `prefers-reduced-motion`.
Tabs do not require motion for state communication.
Affected properties
transformopacityAPI Reference
Tabs
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
defaultValue | string | - | - | Initially active tab. |
value | string | - | - | Controlled active tab. |
onValueChange | (value: string) => void | - | - | Tab change handler. |
orientation | "horizontal" | "vertical" | - | horizontal | Layout direction of the tab list. |
variant | TabsVariant | No | ambient (glinr) | Default look for the list, triggers and panels inside. Each part can still set its own. |
size | TabsSize | No | md | Default density for every part inside. |
TabsList
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
variant | TabsVariant | No | inherits Tabs | Look. Omit to inherit from Tabs or the ambient design style: glinr is the raised pill track (keys), plain is the flat shadcn tabs. Glass is opt-in. |
size | TabsSize | No | md | Density scale. |
TabsTrigger
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string | - | - | Unique value identifying this tab. |
variant | TabsVariant | No | inherits Tabs | Look. Omit to inherit from Tabs or the ambient design style: glinr is the raised pill track (keys), plain is the flat shadcn tabs. Glass is opt-in. |
size | TabsSize | No | md | Density scale. |
disabled | boolean | - | false | Prevents interaction. |
TabsContent
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string | - | - | Value matching the associated trigger. |
variant | TabsVariant | No | inherits Tabs | Look. Omit to inherit from Tabs or the ambient design style: glinr is the raised pill track (keys), plain is the flat shadcn tabs. Glass is opt-in. |
size | TabsSize | No | - | Auto-generated from TypeScript source. |
Source
Import directly from the package or browse the source on GitHub. Click any file to view it.
Generated API Snapshot
Beta
Generated API Snapshot
BetaAuto-extracted from TypeScript source in packages/ui/src/components/tabs.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.
Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata
Primary Props Type
TabsProps
TabsContentProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | TabsSize | No | - | - |
variant | TabsVariant | No | - | - |
TabsListProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | TabsSize | No | - | - |
variant | TabsVariant | No | - | - |
TabsProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | TabsSize | No | - | Default size for every part inside. |
variant | TabsVariant | No | - | Default look for every list, trigger and panel inside. Each part can still set its own. |
TabsTriggerProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | TabsSize | No | - | - |
variant | TabsVariant | No | - | - |