Tab Navigation
Tab navigation allows users to switch between different views or content sections within the same context. Tabs provide a clean way to organize related information while keeping everything accessible on a single page.
Interactive Demo
Basic Tab Navigation
Simple tabs for switching between content sections
Standard Tabs
Basic tab navigation with content switching
This is the overview content. Use tabs to organize related information.
<TabNavigation tabs={tabs} activeTab={active} />Tabs with Icons
Icons help users quickly identify tab content
Active tab: dashboard
<TabNavigation tabs={tabsWithIcons} />Usage
<script>
import TabNavigation from '$lib/shared/components/navigation/TabNavigation.svelte';
let activeTab = $state('overview');
const tabs = [
{ id: 'overview', label: 'Overview' },
{ id: 'details', label: 'Details' },
{ id: 'settings', label: 'Settings' }
];
</script>
<TabNavigation
{tabs}
{activeTab}
onTabChange={(id) => activeTab = id}
/> API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | Tab[] | required | Array of tab objects |
activeTab | string | required | ID of the currently active tab |
onTabChange | (id: string) => void | undefined | Callback when tab is clicked |
class | string | '' | Additional CSS classes |
Tab Object
| Property | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique identifier for the tab |
label | string | ✓ | Display text for the tab |
icon | string | - | Path to icon (relative to /svg/) |
href | string | - | URL for link-style tabs |
Features
Icon Support
Add icons to tabs for better visual recognition:
const tabs = [
{ id: 'home', label: 'Home', icon: 'ui_icons/home' },
{ id: 'profile', label: 'Profile', icon: 'ui_icons/user' }
]; Link Tabs
Create tabs that navigate to different URLs:
const tabs = [
{ id: 'profile', label: 'Profile', href: '/settings/profile' },
{ id: 'security', label: 'Security', href: '/settings/security' }
]; Responsive Behavior
Tabs automatically adapt to available space:
- Desktop: All tabs visible with comfortable spacing
- Mobile: Horizontal scroll for overflow with touch-friendly targets
- Touch targets: Minimum 44px height maintained on all devices
Styling
CSS Variables
The component uses these CSS variables for theming:
--typography-caption-size /* Tab label size */
--typography-caption-color /* Inactive tab color */
--typography-heading-color /* Active tab color */
--primary /* Active tab accent */
--border /* Tab container border */ Custom Styling
Apply custom styles via the class prop:
<TabNavigation
{tabs}
{activeTab}
class="custom-tabs"
/>
<style>
:global(.custom-tabs .tab-item) {
padding: var(--space-2) var(--space-3);
font-size: var(--typography-caption-size);
}
</style> Accessibility
Keyboard Navigation
- Tab: Move focus to next tab
- Shift + Tab: Move focus to previous tab
- Arrow keys: Navigate between tabs (when focused)
- Enter/Space: Activate focused tab
ARIA Attributes
The component includes proper ARIA attributes:
role="tablist"on containerrole="tab"on each tabaria-selectedfor active statearia-labelfor screen reader context
Focus Management
- Visible focus indicators for keyboard navigation
- Focus trap within tab list when using arrow keys
- Automatic focus restoration when switching tabs
Design Decisions
Visual Hierarchy
Tabs use typography and minimal borders to create hierarchy:
- Active tabs have increased font weight and primary color accent
- Underline indicator shows current selection
- Hover states provide visual feedback
Mobile-First Approach
The component prioritizes mobile usability:
- Touch-friendly tap targets (minimum 44px)
- Horizontal scrolling for overflow
- Smooth scroll behavior with momentum
Performance
- CSS transitions for smooth state changes
- Minimal DOM manipulation
- Event delegation for click handlers
Common Patterns
Tab with Content Panels
<script>
let activeTab = $state('tab1');
</script>
<TabNavigation
{tabs}
{activeTab}
onTabChange={(id) => activeTab = id}
/>
<div class="tab-content">
{#if activeTab === 'tab1'}
<Tab1Content />
{:else if activeTab === 'tab2'}
<Tab2Content />
{:else if activeTab === 'tab3'}
<Tab3Content />
{/if}
</div> Lazy Loading Content
<script>
let activeTab = $state('overview');
let content = $state(null);
$effect(() => {
// Load content when tab changes
loadTabContent(activeTab).then(data => {
content = data;
});
});
</script> Disabled Tabs
// Add disabled property to tab objects
const tabs = [
{ id: 'general', label: 'General' },
{ id: 'advanced', label: 'Advanced', disabled: true }
]; Best Practices
- Limit tab count: Keep to 5-7 tabs maximum for usability
- Clear labels: Use concise, descriptive tab labels
- Logical order: Arrange tabs in order of importance or workflow
- Persistent state: Consider saving active tab in URL or localStorage
- Loading states: Show feedback when tab content is loading
- Error handling: Gracefully handle failed content loads
Related Components
- Toolbar: For grouping actions rather than content sections
- Table of Contents: For navigating within long documents
- Pagination: For navigating through sequential pages