Tabs

Material 3 styled tab navigation with optional counts, content slots, and animated active indicators.

Installation

typescript
import { Tabs } from '@happyvertical/smrt-svelte';

Basic Usage

Simple tab navigation with controlled active state.

svelte
<script lang="ts">
  import { Tabs } from '@happyvertical/smrt-svelte';

  const tabs = [
    { id: 'overview', label: 'Overview' },
    { id: 'details', label: 'Details' },
    { id: 'settings', label: 'Settings' }
  ];

  let active = $state('overview');
</script>

<Tabs
  tabs={tabs}
  active={active}
  onchange={(id) => active = id}
/>

With Counts

Display counts next to tab labels.

typescript
const tabs = [
  { id: 'all', label: 'All', count: 42 },
  { id: 'active', label: 'Active', count: 28 },
  { id: 'pending', label: 'Pending', count: 14 }
];

With Content Slot

Render tab content using the children snippet.

svelte
<Tabs tabs={tabs} {active} onchange={(id) => active = id}>
  {#if active === 'overview'}
    <p>Overview content</p>
  {:else if active === 'details'}
    <p>Details content</p>
  {:else}
    <p>Settings content</p>
  {/if}
</Tabs>

Size Variants

Three sizes available: small, medium (default), and large.

svelte
<Tabs tabs={tabs} {active} size="sm" />
<Tabs tabs={tabs} {active} size="md" />
<Tabs tabs={tabs} {active} size="lg" />

Variants

Primary (centered indicator) or secondary (full-width indicator).

svelte
<Tabs tabs={tabs} {active} variant="primary" />
<Tabs tabs={tabs} {active} variant="secondary" />

Disabled Tabs

Mark individual tabs as disabled.

typescript
const tabs = [
  { id: 'active', label: 'Active' },
  { id: 'disabled', label: 'Disabled', disabled: true }
];

Props

PropTypeDefaultDescription
tabs *Tab[]-Array of tab definitions
active *string-ID of the currently active tab
onchange (id: string) => voidundefinedCallback when tab changes
size 'sm' | 'md' | 'lg''md'Tab size variant
variant 'primary' | 'secondary''primary'Visual style variant
children SnippetundefinedContent slot for tab panels

TypeScript

typescript
import { Tabs } from '@happyvertical/smrt-svelte';

interface Tab {
  id: string;
  label: string;
  count?: number;
  disabled?: boolean;
}

interface Props {
  tabs: Tab[];
  active: string;
  onchange?: (id: string) => void;
  size?: 'sm' | 'md' | 'lg';
  variant?: 'primary' | 'secondary';
  children?: Snippet;
}

Accessibility

  • Uses role="tablist" and role="tab"
  • Supports aria-selected for active state
  • Tab panels linked via aria-controls
  • Keyboard navigation supported