# Tabs

> A tablist compound with roving-tabindex keyboard navigation, automatic or manual activation, and an accent-underline or segmented visual style.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Navigation
- Tags: tabs, tablist, roving-tabindex, compound, navigation
- Docs: https://fancy-ui.rama.app/docs/components/tabs
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/tabs

## Import

```svelte
<script lang="ts">
  import { Tabs } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { Tabs } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `""` | The active tab's value, bindable. |
| `onValueChange` | `(value: string) => void` | — | Called with the new value whenever the active tab changes. |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | The tablist's stacking axis and which arrow-key pair moves it. |
| `activation` | `"automatic" \| "manual"` | `"automatic"` | Whether arrowing to a trigger selects it immediately, or only moves focus. |
| `variant` | `"underline" \| "segmented"` | `"underline"` | Accent underline, or a segmented pill rail. |
| `class` | `string` | — | Additional CSS classes, merged onto the root. |
| `ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the root element. |
| `sound` | `boolean` | `false` | Plays select when the active tab actually changes, once the user has enabled sound |
| `TabsList.class` | `string` | — | Additional CSS classes, merged onto the tablist. |
| `TabsList.ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the tablist element. |
| `TabsTrigger.value` (required) | `string` | — | This trigger's value — which TabsContent it activates. |
| `TabsTrigger.disabled` | `boolean` | `false` | Disables just this trigger; it is skipped by the arrows and Home/End. |
| `TabsTrigger.class` | `string` | — | Additional CSS classes, merged onto the trigger button. |
| `TabsTrigger.ref` | `HTMLButtonElement \| null` | `null` | Bindable reference to the trigger's button element. |
| `TabsContent.value` (required) | `string` | — | Which TabsTrigger shows this panel. |
| `TabsContent.forceMount` | `boolean` | `false` | Keeps this panel mounted (with hidden) even while inactive, instead of unmounting it entirely. |
| `TabsContent.class` | `string` | — | Additional CSS classes, merged onto the panel. |
| `TabsContent.ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the panel element. |

## Snippets

| Snippet | Description |
| --- | --- |
| `children` | A TabsList and one or more TabsContents. |
| `TabsList.children` | The TabsTriggers. |
| `TabsTrigger.children` | The trigger's content, typically the tab's label. |
| `TabsContent.children` | The panel's content. |

## Examples

### Basic Usage

Three tabs, automatic activation, the underline variant.

```svelte
<script lang="ts">
	import { Tabs, TabsList, TabsTrigger, TabsContent } from "fancy-ui-svelte";

	let section = $state("account");
</script>

<Tabs sound bind:value={section}>
	<TabsList>
		<TabsTrigger value="account">Account</TabsTrigger>
		<TabsTrigger value="security">Security</TabsTrigger>
		<TabsTrigger value="billing">Billing</TabsTrigger>
	</TabsList>
	<TabsContent value="account">Manage your profile, name, and avatar.</TabsContent>
	<TabsContent value="security">Update your password and two-factor settings.</TabsContent>
	<TabsContent value="billing">View invoices and update your payment method.</TabsContent>
</Tabs>
```

### Segmented Variant

The pill-rail visual style instead of the accent underline.

```svelte
<script lang="ts">
	import { Tabs, TabsList, TabsTrigger, TabsContent } from "fancy-ui-svelte";

	let view = $state("preview");
</script>

<Tabs sound bind:value={view} variant="segmented">
	<TabsList>
		<TabsTrigger value="preview">Preview</TabsTrigger>
		<TabsTrigger value="code">Code</TabsTrigger>
	</TabsList>
	<TabsContent value="preview">The rendered component.</TabsContent>
	<TabsContent value="code">The component's source.</TabsContent>
</Tabs>
```

### Manual Activation

Arrow keys only move focus; Enter/Space or a click selects.

```svelte
<script lang="ts">
	import { Tabs, TabsList, TabsTrigger, TabsContent } from "fancy-ui-svelte";

	let step = $state("one");
</script>

<Tabs sound bind:value={step} activation="manual">
	<TabsList>
		<TabsTrigger value="one">Step one</TabsTrigger>
		<TabsTrigger value="two">Step two</TabsTrigger>
		<TabsTrigger value="three">Step three</TabsTrigger>
	</TabsList>
	<TabsContent value="one">
		Arrow keys only move focus here — press Enter or Space to select.
	</TabsContent>
	<TabsContent value="two">Step two's content.</TabsContent>
	<TabsContent value="three">Step three's content.</TabsContent>
</Tabs>
```

### Vertical Tabs

Stacked in a column, with Up/Down driving the roving tabindex.

```svelte
<script lang="ts">
	import { Tabs, TabsList, TabsTrigger, TabsContent } from "fancy-ui-svelte";

	let section = $state("general");
</script>

<Tabs sound bind:value={section} orientation="vertical">
	<div class="flex gap-6">
		<TabsList>
			<TabsTrigger value="general">General</TabsTrigger>
			<TabsTrigger value="notifications">Notifications</TabsTrigger>
			<TabsTrigger value="advanced">Advanced</TabsTrigger>
		</TabsList>
		<div class="flex-1">
			<TabsContent value="general">General settings live here.</TabsContent>
			<TabsContent value="notifications">Choose what you get notified about.</TabsContent>
			<TabsContent value="advanced">Advanced, rarely-touched settings.</TabsContent>
		</div>
	</div>
</Tabs>
```

### Disabled Tab

One trigger unavailable — skipped by the arrows and Home/End.

```svelte
<script lang="ts">
	import { Tabs, TabsList, TabsTrigger, TabsContent } from "fancy-ui-svelte";

	let plan = $state("starter");
</script>

<Tabs sound bind:value={plan}>
	<TabsList>
		<TabsTrigger value="starter">Starter</TabsTrigger>
		<TabsTrigger value="team" disabled>Team</TabsTrigger>
		<TabsTrigger value="enterprise">Enterprise</TabsTrigger>
	</TabsList>
	<TabsContent value="starter">Starter plan details.</TabsContent>
	<TabsContent value="team">Team plan details — requires an upgrade.</TabsContent>
	<TabsContent value="enterprise">Enterprise plan details.</TabsContent>
</Tabs>
```
