motif svelteArc

Tabs ported

Switch between related content in the same context.

Peer views of the same object with sliding selection indicator, horizontally scrollable overflow with edge buttons, and spring panel height.

Live specimen

Loading demo…

Guidance

When to use

  • Peer views of the same object, such as Overview, Activity, and Settings.
  • Panels with different heights, where the container should spring between them.
  • Long tab sets that need to scroll horizontally with edge buttons.

When not to use

  • Use Segmented Control for a compact value toggle not tied to panels.
  • Use Accordion for stacked sections people read in order.
  • Use Liquid Tab Bar or Morph Nav for app-level navigation between routes.

Installation

pnpm dlx shadcn-svelte@latest add @arcui/tabs

Usage

<script lang="ts">
  import { Tabs, TabsList, TabsTrigger, TabsContent } from '$lib/components/tabs';
</script>

<Tabs defaultValue="overview">
  <TabsList aria-label="Project Sections">
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="activity">Activity</TabsTrigger>
    <TabsTrigger value="settings">Settings</TabsTrigger>
  </TabsList>
  <TabsContent value="overview">
    <p>Project summary and performance metrics.</p>
  </TabsContent>
  <TabsContent value="activity">
    <p>Recent audit logs and team events.</p>
  </TabsContent>
  <TabsContent value="settings">
    <p>Configure team permissions and notifications.</p>
  </TabsContent>
</Tabs>

Variants & Examples

Standard Tab Set

Default uncontrolled tab list with 3 panels.

<Tabs defaultValue="tab1">
  <TabsList>
    <TabsTrigger value="tab1">One</TabsTrigger>
    <TabsTrigger value="tab2">Two</TabsTrigger>
  </TabsList>
  <TabsContent value="tab1">First</TabsContent>
  <TabsContent value="tab2">Second</TabsContent>
</Tabs>

Controlled Active Tab

Two-way binding with Svelte 5 bind:value rune.

<Tabs bind:value={activeTab}>
  <TabsList><TabsTrigger value="a">A</TabsTrigger></TabsList>
  <TabsContent value="a">Panel A</TabsContent>
</Tabs>

Disabled Tab

Triggers can be disabled individually to prevent activation.

<TabsTrigger value="pro" disabled>Pro Only</TabsTrigger>

API Reference

PropTypeDefaultDescription
valuestring—Controlled active tab value. Supports two-way bind:value.
defaultValuestring''Initial active tab when uncontrolled.
onValueChange(value: string) => void—Called when the active tab changes.
childrenSnippet—Tabs content comprising TabsList and TabsContent elements.

Keyboard Interactions

KeyAction
ArrowLeft / ArrowRightMoves between tabs and activates them.
Home / EndJumps directly to the first or last tab.
TabMoves focus from the tab list into the active panel.

Accessibility

  • Bits UI provides role="tablist", role="tab", role="tabpanel", aria-selected, and aria-controls.
  • The outgoing panel is made inert so it cannot take focus.
  • Overflow scroll buttons are labelled "Scroll tabs left" and "Scroll tabs right"; give TabsList an aria-label.

Motion

Phase 1 still-state: selection pill renders statically at active tab; panels render content without direction slide. Phase 2 springs selection pill morph spring (motionTokens.spring.morph), height animation on tab switch, and left/right enter/exit transitions.

Notes for AI

  • Use for peer views of the same object. Use Segmented Control for a compact value toggle that is not tied to panels.
  • Every TabsTrigger value needs a matching TabsContent. Long lists scroll horizontally on their own.

Source of truth: registry/components/tabs/tabs.tsx