Tabs
Organize content into tabbed sections. Supports pill and link variants, icons, vertical layout, controlled state, and custom content rendering.
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 |
slot | string | - |
class | string | - |
ui | Record<Slot, Class> | - |