Tabs
Tab navigation component for organizing content into switchable sections.
Tab Variants
Standard Tabs
Basic horizontal tabs with underline indicator
Overview Content
This is the overview tab content. It provides general information about the property or item being displayed.
Features Content
List of features and amenities available with this property.
Specifications Content
Detailed technical specifications and measurements.
Reviews Content
Customer reviews and ratings for this property.
Pills Style Tabs
Tabs with pill-style background
Showing all properties
Properties available for sale
Properties available for rent
Recently sold properties
Tabs with Icons
Tabs enhanced with icons
Property overview and details
Location information and map
Pricing and payment options
Tabs with Badges
Tabs with notification badges
You have 3 new messages
12 new notifications
No new updates
Real Estate Use Cases
Property Details Tabs
Property Details
- 3 Bedrooms, 2 Bathrooms
- 150 m² Living Space
- Built in 2020
- Energy Class A+
Floor Plans
Interactive floor plans would be displayed here
Virtual Tour
360° virtual tour interface
Neighborhood Information
Schools, transport, shopping nearby
Contact Agent
Agent contact form and information
Implementation Guide
HTML Structure
<!-- Standard Tabs -->
<div class="lyd-tabs">
<div class="lyd-tabs-list">
<button class="lyd-tab active" onclick="switchTab(event, 'tab1')">Tab 1</button>
<button class="lyd-tab" onclick="switchTab(event, 'tab2')">Tab 2</button>
<button class="lyd-tab" onclick="switchTab(event, 'tab3')">Tab 3</button>
</div>
<div class="lyd-tab-panels">
<div id="tab1" class="lyd-tab-panel active">
<p>Tab 1 content</p>
</div>
<div id="tab2" class="lyd-tab-panel">
<p>Tab 2 content</p>
</div>
<div id="tab3" class="lyd-tab-panel">
<p>Tab 3 content</p>
</div>
</div>
</div>
<!-- Pills Style -->
<div class="lyd-tabs-list pills">
<button class="lyd-tab active">Option 1</button>
<button class="lyd-tab">Option 2</button>
</div>
<!-- Tab with Icon and Badge -->
<button class="lyd-tab">
<span class="lyd-tab-icon">
<svg>...</svg>
Messages
</span>
<span class="lyd-tab-badge">3</span>
</button>
JavaScript Tab Switching
// Switch tabs
function switchTab(event, tabId) {
// Get tab container
const tabContainer = event.target.closest('.lyd-tabs');
// Remove active from all tabs
tabContainer.querySelectorAll('.lyd-tab').forEach(tab => {
tab.classList.remove('active');
});
// Remove active from all panels
tabContainer.querySelectorAll('.lyd-tab-panel').forEach(panel => {
panel.classList.remove('active');
});
// Add active to clicked tab
event.target.classList.add('active');
// Add active to corresponding panel
const panel = tabContainer.querySelector(`#${tabId}`);
if (panel) {
panel.classList.add('active');
}
}
// Keyboard navigation
document.querySelectorAll('.lyd-tabs-list').forEach(tabList => {
const tabs = tabList.querySelectorAll('.lyd-tab');
tabs.forEach((tab, index) => {
tab.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') {
const nextTab = tabs[index + 1] || tabs[0];
nextTab.focus();
nextTab.click();
} else if (e.key === 'ArrowLeft') {
const prevTab = tabs[index - 1] || tabs[tabs.length - 1];
prevTab.focus();
prevTab.click();
}
});
});
});
React/Next.js Component
// components/Tabs.tsx
import { useState, ReactNode } from 'react';
interface Tab {
id: string;
label: string;
icon?: ReactNode;
badge?: number;
content: ReactNode;
}
interface TabsProps {
tabs: Tab[];
variant?: 'underline' | 'pills';
orientation?: 'horizontal' | 'vertical';
defaultTab?: string;
}
export const Tabs = ({
tabs,
variant = 'underline',
orientation = 'horizontal',
defaultTab
}: TabsProps) => {
const [activeTab, setActiveTab] = useState(defaultTab || tabs[0]?.id);
const tabListClasses = [
'lyd-tabs-list',
variant === 'pills' && 'pills'
].filter(Boolean).join(' ');
const tabsClasses = [
'lyd-tabs',
orientation === 'vertical' && 'vertical'
].filter(Boolean).join(' ');
return (
<div className={tabsClasses}>
<div className={tabListClasses}>
{tabs.map((tab) => (
<button
key={tab.id}
className={`lyd-tab ${activeTab === tab.id ? 'active' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.icon && (
<span className="lyd-tab-icon">
{tab.icon}
{tab.label}
</span>
)}
{!tab.icon && tab.label}
{tab.badge && (
<span className="lyd-tab-badge">{tab.badge}</span>
)}
</button>
))}
</div>
<div className="lyd-tab-panels">
{tabs.map((tab) => (
<div
key={tab.id}
id={tab.id}
className={`lyd-tab-panel ${activeTab === tab.id ? 'active' : ''}`}
>
{tab.content}
</div>
))}
</div>
</div>
);
};
API Reference
| Class | Description |
|---|---|
.lyd-tabs |
Main tabs container |
.lyd-tabs-list |
Tab buttons container |
.lyd-tab |
Individual tab button |
.lyd-tab-panels |
Tab content panels container |
.lyd-tab-panel |
Individual tab panel |
.lyd-tab-icon |
Tab icon wrapper |
.lyd-tab-badge |
Tab notification badge |
.pills |
Pills style variant |
.vertical |
Vertical orientation |
.active |
Active tab/panel state |
Accessibility & Best Practices
Keyboard Navigation
- Tab to focus tab list
- Arrow keys to navigate between tabs
- Enter/Space to activate tab
- Tab to move into panel content
ARIA Attributes
- role="tablist" on tab container
- role="tab" on tab buttons
- role="tabpanel" on content panels
- aria-selected on active tab
- aria-controls linking tabs to panels
Best Practices
- Keep tab labels short and descriptive
- Limit to 5-7 tabs maximum
- Use icons to enhance recognition
- Provide visual feedback for active state
- Consider vertical tabs for many items
Content Organization
- Group related content logically
- Order tabs by importance/frequency
- Maintain consistent panel layouts
- Preserve state when switching tabs