Tabs
A tabbed interface component for organizing content into separate views accessible via tab navigation.
Features
- Multiple tab variants (line, enclosed, pills)
- Horizontal and vertical orientation
- Active state indicators
- Badge support for notifications
- Icon support
- Keyboard navigation
- Swipeable content (mobile)
- Lazy loading support
Usage
Web (React)
import { Tabs, TabList, Tab, TabPanels, TabPanel } from '@cuppa/ui'
function MyComponent() {
return (
<Tabs defaultIndex={0}>
<TabList>
<Tab>Profile</Tab>
<Tab>Settings</Tab>
<Tab>Notifications</Tab>
</TabList>
<TabPanels>
<TabPanel>
<h2>Profile Content</h2>
<p>User profile information...</p>
</TabPanel>
<TabPanel>
<h2>Settings Content</h2>
<p>Application settings...</p>
</TabPanel>
<TabPanel>
<h2>Notifications Content</h2>
<p>Notification preferences...</p>
</TabPanel>
</TabPanels>
</Tabs>
)
}
iOS (SwiftUI)
import CuppaUI
struct MyView: View {
@State private var selectedTab = 0
var body: some View {
CuppaTabs(selection: $selectedTab) {
CuppaTab(title: "Profile", index: 0) {
VStack {
Text("Profile Content")
Text("User profile information...")
}
}
CuppaTab(title: "Settings", index: 1) {
VStack {
Text("Settings Content")
Text("Application settings...")
}
}
CuppaTab(title: "Notifications", index: 2) {
VStack {
Text("Notifications Content")
Text("Notification preferences...")
}
}
}
}
}
Android (Jetpack Compose)
import com.cuppa.ui.components.CuppaTabs
import androidx.compose.runtime.*
@Composable
fun MyScreen() {
var selectedIndex by remember { mutableStateOf(0) }
CuppaTabs(
selectedIndex = selectedIndex,
onTabSelected = { selectedIndex = it }
) {
CuppaTab(title = "Profile") {
Column {
Text("Profile Content", style = MaterialTheme.typography.h5)
Text("User profile information...")
}
}
CuppaTab(title = "Settings") {
Column {
Text("Settings Content", style = MaterialTheme.typography.h5)
Text("Application settings...")
}
}
CuppaTab(title = "Notifications") {
Column {
Text("Notifications Content", style = MaterialTheme.typography.h5)
Text("Notification preferences...")
}
}
}
}
Props
| Prop | Type | Default | Description | |------|------|---------|-------------| | defaultIndex | number | 0 | Initially selected tab index | | onChange | function | - | Callback when tab changes | | variant | string | 'line' | Tab style (line, enclosed, pills) | | orientation | string | 'horizontal' | Tab orientation | | fitted | boolean | false | Stretch tabs to fill width | | isLazy | boolean | false | Lazy load tab content |
Variants
Line
Underline indicator below active tab (default)
Enclosed
Tabs with borders and background
Pills
Rounded pill-shaped tabs
Examples
With Icons
<Tabs>
<TabList>
<Tab>
<UserIcon />
Profile
</Tab>
<Tab>
<SettingsIcon />
Settings
</Tab>
<Tab>
<BellIcon />
Notifications
</Tab>
</TabList>
<TabPanels>
{/* ... panels ... */}
</TabPanels>
</Tabs>
With Badges
<Tabs>
<TabList>
<Tab>
Messages
<Badge>3</Badge>
</Tab>
<Tab>
Notifications
<Badge>12</Badge>
</Tab>
</TabList>
<TabPanels>
{/* ... panels ... */}
</TabPanels>
</Tabs>
Vertical Tabs
<Tabs orientation="vertical">
<TabList>
<Tab>General</Tab>
<Tab>Security</Tab>
<Tab>Privacy</Tab>
</TabList>
<TabPanels>
{/* ... panels ... */}
</TabPanels>
</Tabs>
Accessibility
- Arrow key navigation between tabs
- Home/End keys for first/last tab
- Tab panels use proper ARIA roles
- Keyboard focus visible
- Screen reader support
Best Practices
- Keep tab labels short and descriptive
- Use 3-7 tabs maximum
- Don't nest tabs within tabs
- Lazy load heavy content
- Maintain consistent content structure
- Use icons to enhance recognition