Tabs
Organize content into tabbed sections. Supports pill and link variants, icons, vertical layout, controlled state, and custom content rendering. Tabs switch panels within one page. To navigate between routes, use NavigationMenu.
Playground
Experiment with different props in real-time.
Basic Usage
Pass an array of items with label, value, and content.
<script lang="ts">
import { Tabs } from 'sv5ui';
const items = [
{ label: 'Account', value: 'account', content: 'Manage your account settings and preferences.' },
{ label: 'Settings', value: 'settings', content: 'Configure application settings and themes.' },
{ label: 'Notifications', value: 'notifications', content: 'Control your notification preferences.' }
];
</script>
<Tabs {items} />Variants
2 visual styles.
Pill
Link
<!-- Pill variant (default) -->
<Tabs variant="pill" {items} />
<!-- Link variant -->
<Tabs variant="link" {items} />Sizes
4 sizes.
xs
sm
md
lg
<Tabs size="xs" {items} />
<Tabs size="sm" {items} />
<Tabs size="md" {items} />
<Tabs size="lg" {items} />Colors
Semantic color schemes.
primary
secondary
success
error
<Tabs color="primary" {items} />
<Tabs color="secondary" {items} />
<Tabs color="success" {items} />
<Tabs color="error" {items} />With Icons
Add leading icons to tab triggers.
<Tabs items={[
{ label: 'Account', icon: 'lucide:user', value: 'account', content: 'Manage your account.' },
{ label: 'Settings', icon: 'lucide:settings', value: 'settings', content: 'Configure preferences.' },
{ label: 'Notifications', icon: 'lucide:bell', value: 'notifications', content: 'Control alerts.' }
]} />Vertical
Set orientation="vertical" for side-by-side layout.
<Tabs orientation="vertical" items={[
{ label: 'Profile', value: 'profile', content: 'View and edit your profile details.' },
{ label: 'Security', value: 'security', content: 'Update password and 2FA settings.' },
{ label: 'Billing', value: 'billing', content: 'Manage subscription and payments.' }
]} />Disabled Items
Disable individual tabs.
<Tabs items={[
{ label: 'Active', value: 'active', content: 'This tab is clickable.' },
{ label: 'Disabled', value: 'disabled', content: 'Cannot view.', disabled: true },
{ label: 'Also Active', value: 'also-active', content: 'This tab works normally.' }
]} />Without Content Panels
Set content={false} to use tabs as a selector only, rendering your own content.
Active tab: account
<script lang="ts">
import { Tabs } from 'sv5ui';
let value = $state('account');
</script>
<!-- Tabs without content panels -->
<Tabs
bind:value
content={false}
items={[
{ label: 'Account', value: 'account' },
{ label: 'Settings', value: 'settings' },
{ label: 'Billing', value: 'billing' }
]}
/>
<!-- Render your own content based on active tab -->
<p>Active tab: {value}</p>Controlled
Use bind:value for programmatic control.
<script lang="ts">
import { Tabs, Button } from 'sv5ui';
let value = $state('account');
</script>
<div class="flex gap-2 mb-4">
<Button label="Go to Account" size="sm" variant="outline" onclick={() => value = 'account'} />
<Button label="Go to Settings" size="sm" variant="outline" onclick={() => value = 'settings'} />
</div>
<Tabs bind:value {items} />Custom Body
Use the body snippet for fully custom panel content.
account Details
Custom rendered content for Account.
<Tabs items={[
{ label: 'Account', value: 'account' },
{ label: 'Settings', value: 'settings' },
{ label: 'Notifications', value: 'notifications' }
]}>
{#snippet body({ item, active })}
{#if active}
<div class="space-y-2">
<h3 class="font-semibold capitalize">{item.value} Details</h3>
<p class="text-sm text-on-surface/60">Custom rendered content for {item.label}.</p>
</div>
{/if}
{/snippet}
</Tabs>UI Slots
Use the ui prop to override classes on internal elements.
| Slot | Description |
|---|---|
root | Root tabs container |
list | Tab list wrapper |
indicator | Active tab indicator (animated) |
trigger | Individual tab trigger button |
leadingIcon | Icon before tab label |
label | Tab label text |
content | Tab panel content wrapper |
Snippets
Each snippet receives item, index, and active as props.
| Snippet | Props | Description |
|---|---|---|
leading | item, index, active | Custom leading section (replaces icon) |
label | item, index, active | Custom label section |
trailing | item, index, active | Custom trailing section |
body | item, index, active | Custom content for tab panel |
Props
| Prop | Type | Default |
|---|---|---|
items | TabsItem[] | [] |
value | string | - |
defaultValue | string | - |
variant | 'pill' | 'link' | 'pill' |
color | ColorType | 'primary' |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' |
orientation | 'horizontal' | 'vertical' | 'horizontal' |
content | boolean | true |
activationMode | 'automatic' | 'manual' | 'automatic' |
disabled | boolean | false |
loop | boolean | true |
onValueChange | (value) => void | - |
ref | HTMLElement | null | null |
class | string | - |
ui | Record<Slot, Class> | - |
Item Props
| Prop | Type | Default |
|---|---|---|
label | string | - |
icon | string | - |
value | string | index |
content | string | - |
disabled | boolean | false |
class | string | - |
ui | Record<Slot, Class> | - |