Glin UI
Primitive / Molecule

Tabs

Tabbed interface for switching between grouped content panels.

Edit on GitHub

Lumen web app

Production, deployed 12 minutes ago

Live
  • AKAva Kim merged release 2.4 into main12 min ago
  • JRJon Reyes commented on the pricing page1 h ago
  • SPSara Patel invited two teammatesYesterday

Installation

Install from
pnpm dlx @glinui/cli@latest add tabs

Prefer the package?

Usage

Underline with icons

The underline look with icons, a count badge and a disabled tab.

12 members across 3 teams.

"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.

Glass tab content.
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

Liquid tab surface.
Matte tab surface.
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

KeyAction
Arrow Left / RightNavigate between tab triggers.
Enter / SpaceSelect 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

transformopacity

API Reference

Tabs

PropTypeRequiredDefaultDescription
defaultValuestring--Initially active tab.
valuestring--Controlled active tab.
onValueChange(value: string) => void--Tab change handler.
orientation"horizontal" | "vertical"-horizontalLayout direction of the tab list.
variantTabsVariantNoambient (glinr)Default look for the list, triggers and panels inside. Each part can still set its own.
sizeTabsSizeNomdDefault density for every part inside.

TabsList

PropTypeRequiredDefaultDescription
variantTabsVariantNoinherits TabsLook. 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.
sizeTabsSizeNomdDensity scale.

TabsTrigger

PropTypeRequiredDefaultDescription
valuestring--Unique value identifying this tab.
variantTabsVariantNoinherits TabsLook. 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.
sizeTabsSizeNomdDensity scale.
disabledboolean-falsePrevents interaction.

TabsContent

PropTypeRequiredDefaultDescription
valuestring--Value matching the associated trigger.
variantTabsVariantNoinherits TabsLook. 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.
sizeTabsSizeNo-Auto-generated from TypeScript source.

Source

Import directly from the package or browse the source on GitHub. Click any file to view it.

Import

import { Tabs } from "@glinui/ui"

Source Files

Dependencies

@glinui/ui

Generated API Snapshot

Beta

Auto-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

PropTypeRequiredDefaultDescription
sizeTabsSizeNo--
variantTabsVariantNo--

TabsListProps

PropTypeRequiredDefaultDescription
sizeTabsSizeNo--
variantTabsVariantNo--

TabsProps

PropTypeRequiredDefaultDescription
sizeTabsSizeNo-Default size for every part inside.
variantTabsVariantNo-Default look for every list, trigger and panel inside. Each part can still set its own.

TabsTriggerProps

PropTypeRequiredDefaultDescription
sizeTabsSizeNo--
variantTabsVariantNo--