Tabs

Switch between related panels. The active-tab indicator physically slides between tabs — seamui's layout-animation pattern.

Manage your account. The indicator springs between tabs.
tsx
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "@/registry/seam/ui/tabs"

export default function TabsDemo() {
  return (
    <Tabs defaultValue="account" className="w-80">
      <TabsList>
        <TabsTrigger value="account">Account</TabsTrigger>
        <TabsTrigger value="password">Password</TabsTrigger>
        <TabsTrigger value="team">Team</TabsTrigger>
      </TabsList>
      <TabsContent
        value="account"
        className="text-muted-foreground pt-2 text-sm"
      >
        Manage your account. The indicator springs between tabs.
      </TabsContent>
      <TabsContent
        value="password"
        className="text-muted-foreground pt-2 text-sm"
      >
        Change your password here.
      </TabsContent>
      <TabsContent value="team" className="text-muted-foreground pt-2 text-sm">
        Invite and manage your team.
      </TabsContent>
    </Tabs>
  )
}
bunx --bun @seamui/cli@latest add tabs

Notes

  • The indicator is a shared-layout motion.span (layoutId) inside the active tab — selection change springs it to the new tab with springs.snappy, fully interruptible. Each Tabs instance scopes its own layoutId so multiple groups never fight.
  • Triggers reuse buttonVariants classes on the composite-safe element (no Button wrapper) so Base UI's roving arrow-key focus keeps working.
  • Full role="tablist" semantics with arrow-key navigation and automatic activation; controlled via value / onValueChange, or uncontrolled via defaultValue.

Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.