Skip to main content

Tab Navigation

Switch between different views or content sections within the same context

Tags:
navigationtabsuicomponentsaccessibility
Last updated: 2025-09-12T00:00:00.000Z

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

PropTypeDefaultDescription
tabsTab[]requiredArray of tab objects
activeTabstringrequiredID of the currently active tab
onTabChange(id: string) => voidundefinedCallback when tab is clicked
classstring''Additional CSS classes

Tab Object

PropertyTypeRequiredDescription
idstringUnique identifier for the tab
labelstringDisplay text for the tab
iconstring-Path to icon (relative to /svg/)
hrefstring-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' }
];

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 container
  • role="tab" on each tab
  • aria-selected for active state
  • aria-label for 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

  1. Limit tab count: Keep to 5-7 tabs maximum for usability
  2. Clear labels: Use concise, descriptive tab labels
  3. Logical order: Arrange tabs in order of importance or workflow
  4. Persistent state: Consider saving active tab in URL or localStorage
  5. Loading states: Show feedback when tab content is loading
  6. Error handling: Gracefully handle failed content loads
  • Toolbar: For grouping actions rather than content sections
  • Table of Contents: For navigating within long documents
  • Pagination: For navigating through sequential pages