Skip to content

Tabs ​

Introduction ​

The Tabs component provides a flexible, accessible, and highly customizable tabbed navigation interface for organizing content into separate views. It supports multiple visual variants, sizes, icons, controlled and uncontrolled usage, vertical orientation, event triggers (click/hover), and can be composed with either an items array or children panels. Common use cases include dashboards, user profiles, product details, analytics, and more.

Import ​

ts
import { Tabs } from '@odyssee/components';
// Tabs.Panel is available as a static property for flexible composition

LiveCodeEditor examples ​

Basic Tabs ​

Code Éditable
Résultat

Variants ​

Code Éditable
Résultat

Sizes ​

Code Éditable
Résultat

Tabs with Icons ​

Code Éditable
Résultat

Controlled Tabs ​

Code Éditable
Résultat

Event Types (Click & Hover) ​

Code Éditable
Résultat

Use Case: User Profile Sections ​

Code Éditable
Résultat

Props ​

Tabs ​

PropTypeDefaultDescription
itemsTabs.Item[]—Array of tab items (see below for structure).
childrenHTMLElement | HTMLElement[]—Custom children panels (alternative to items).
activeTabstring | Signal<string>—Controlled active tab ID (or Pulse signal).
variant"underline" | "pills" | "enclosed" | "vertical""underline"Visual style of the tabs.
eventType"click" | "hover""click"Event trigger for tab activation.
borderedbooleantrueShow border under tabs (underline/enclosed variants).
fullWidthbooleanfalseTabs take full width of container.
size"sm" | "md" | "lg""md"Size of tab labels.
tablistClassNamestring—Custom class for the tablist container.
contentClassNamestring—Custom class for the content panel container.
onChange(tabId: string, prevTabId: string) => void—Callback fired when the active tab changes.
classNamestring—Additional CSS classes for the root element.
idstringauto-generatedID for the tabs component.
...restBaseComponentProps—Any other base props supported by Odyssee components.

Tabs.Item ​

PropTypeDescription
idstringUnique identifier for the tab.
labelstring | HTMLElementTab label (text or custom element).
contentstring | HTMLElement | HTMLElement[]Content for the tab panel.
iconstring | HTMLElementIcon displayed next to the label.
disabledbooleanDisables the tab.
badgestring | numberBadge displayed next to the label.

Tabs.Panel ​

PropTypeDescription
idstringUnique identifier for the panel.
labelstring | HTMLElementTab label for the panel.
childrenstring | HTMLElement | HTMLElement[]Content for the panel.
iconstring | HTMLElementIcon displayed next to the label.
disabledbooleanDisables the tab.
badgestring | numberBadge displayed next to the label.

Implementation notes ​

  • The component supports both array-based (items) and children-based (Tabs.Panel) composition.
  • Controlled usage is supported via the activeTab prop (string or Pulse signal).
  • Four visual variants: underline, pills, enclosed, and vertical.
  • Tabs can be activated by click or hover (eventType).
  • Icons and badges are supported for tab labels.
  • Disabled tabs are skipped in navigation and visually indicated.
  • Designed for both light and dark themes.
  • All tab panels are rendered, but only the active panel is visible.

Accessibility ​

  • All tab buttons use proper ARIA roles (role="tab", aria-selected, aria-controls).
  • Tab panels use role="tabpanel" and are linked to their tab via aria-labelledby.
  • Keyboard navigation is supported (Tab, Arrow keys).
  • Disabled tabs are not focusable.
  • Focus and active states are clearly styled for usability.
  • Supports vertical orientation with correct ARIA attributes.

Best practices ​

  • Use controlled mode (activeTab as signal + onChange) for full synchronization with your app state.
  • Choose the appropriate variant and size for your layout and design system.
  • Use icons and badges to enhance tab clarity and highlight important sections.
  • Prefer vertical tabs for sidebar navigation or dense layouts.
  • Ensure all tab labels are clear and concise for accessibility.
  • Avoid excessive numbers of tabs; group related content when possible.

Released under the MIT License.