Tabs
Tabs organize content into multiple sections that users can navigate between. The component supports various visual styles, orientations, and interactive behaviors while maintaining accessibility standards.
Source
LLM docs
Package
Examples
8
Properties
60
Playground
Basics
Pass
items with a key, label, and content for each tab; the active tab's content renders below the tab list.Loading demo…
import { Block, Tabs, Text } from '@plocks/ui';
const ITEMS = [
{
key: 'overview',
label: 'Overview',
content: <Text>High-level summary and entry point.</Text>
},
{
key: 'details',
label: 'Details',
content: <Text>Deeper dive into metrics and configuration.</Text>
},
{
key: 'activity',
label: 'Activity',
content: <Text>Recent events, tasks, and notifications.</Text>
}
];
export function Demo() {
return (
<Block fullWidth>
<Tabs items={ITEMS} />
</Block>
);
}Animated transitions
Enable
animated and set animationDuration (in ms) to control how quickly the indicator slides between tabs.Loading demo…
import { Block, Tabs, Text } from '@plocks/ui';
const ITEMS = [
{
key: 'overview',
label: 'Overview',
content: <Text>High-level summary and entry point.</Text>
},
{
key: 'details',
label: 'Details',
content: <Text>Deeper dive into metrics and configuration.</Text>
},
{
key: 'settings',
label: 'Settings',
content: <Text>Manage workspace preferences.</Text>
}
];
export function Demo() {
return (
<Block fullWidth>
<Tabs animated animationDuration={500} items={ITEMS} />
</Block>
);
}Disabled tabs
Show how to disable a tab while capturing interaction attempts through
onDisabledTabPress for auditing or messaging.Loading demo…
import { useState } from 'react';
import { Block, Tabs, Text } from '@plocks/ui';
const ITEMS = [
{
key: 'overview',
label: 'Overview',
content: <Text>High-level snapshot of product activity and health.</Text>
},
{
key: 'analytics',
label: 'Analytics',
content: <Text>Dive into usage metrics, adoption trends, and retention.</Text>
},
{
key: 'billing',
label: 'Billing',
content: <Text>Billing is temporarily disabled while invoices reconcile.</Text>,
disabled: true
},
{
key: 'settings',
label: 'Settings',
content: <Text>Manage workspace preferences and security controls.</Text>
}
];
export function Demo() {
const [lastAttempt, setLastAttempt] = useState<string | null>(null);
return (
<Block fullWidth>
<Tabs items={ITEMS} onDisabledTabPress={setLastAttempt} />
{lastAttempt && (
<Text variant="small" c="muted">
Pressed disabled tab: {lastAttempt}
</Text>
)}
</Block>
);
}Controlled state
Demonstrates controlled tabs that surface the active label and rely on external state updates via
onChange.Loading demo…
import { useState } from 'react';
import { Block, Tabs, Text } from '@plocks/ui';
const ITEMS = [
{
key: 'dashboard',
label: '🏠 Dashboard',
content: <Text>Monitor analytics across teams and products.</Text>
},
{
key: 'settings',
label: '⚙️ Settings',
content: <Text>Configure notifications, permissions, and integrations.</Text>
},
{
key: 'profile',
label: '👤 Profile',
content: <Text>Review contact details, roles, and security options.</Text>
}
];
export function Demo() {
const [activeTab, setActiveTab] = useState('dashboard');
const activeLabel = ITEMS.find((item) => item.key === activeTab)?.label ?? activeTab;
return (
<Block fullWidth>
<Tabs value={activeTab} onChange={setActiveTab} items={ITEMS} />
<Text variant="small" c="muted">
Active tab: {activeLabel}
</Text>
</Block>
);
}Location
Switch tab placement between
start and end to position triggers above or below the associated content.Loading demo…
import { Block, Tabs, Text } from '@plocks/ui';
const LOCATIONS = ['start', 'end'] as const;
const ITEMS = [
{
key: 'home',
label: 'Home',
content: <Text>Home content.</Text>
},
{
key: 'settings',
label: 'Settings',
content: <Text>Update your configuration.</Text>
},
{
key: 'profile',
label: 'Profile',
content: <Text>Profile information.</Text>
}
];
export function Demo() {
return (
<Block fullWidth>
{LOCATIONS.map((location) => (
<Block key={location} fullWidth>
<Text variant="small" c="secondary">{location}</Text>
<Tabs location={location} items={ITEMS} />
</Block>
))}
</Block>
);
}Navigation only
Demonstrates
navigationOnly tabs that render the triggers separately while a custom container handles the content region.Loading demo…
import { useMemo, useState } from 'react';
import { Block, Tabs, Text, useTheme } from '@plocks/ui';
const NAV_ITEMS = [
{ key: 'home', label: 'Home' },
{ key: 'products', label: 'Products' },
{ key: 'about', label: 'About' },
{ key: 'contact', label: 'Contact' }
] as const;
const CONTENT_COPY: Record<typeof NAV_ITEMS[number]['key'], string> = {
home: 'Welcome back! Navigation only mode keeps the tab strip separated from the view.',
products: 'Highlight product cards, filters, or category grids below the navigation.',
about: 'Share the company story, values, and milestones alongside persistent tabs.',
contact: 'Surface support channels and locations while the navigation stays fixed.'
};
export function Demo() {
const theme = useTheme();
const [activeTab, setActiveTab] = useState<typeof NAV_ITEMS[number]['key']>('home');
const items = useMemo(
() => NAV_ITEMS.map(({ key, label }) => ({ key, label, content: null })),
[]
);
return (
<Block fullWidth>
<Tabs
items={items}
value={activeTab}
onChange={(tabKey) => setActiveTab(tabKey as typeof NAV_ITEMS[number]['key'])}
variant="chip"
navigationOnly
/>
<Block bg={theme.backgrounds.surface} borderColor={theme.backgrounds.border} radius="lg" p="lg">
<Text>{CONTENT_COPY[activeTab]}</Text>
</Block>
</Block>
);
}Orientation
Compare horizontal and vertical tab lists to understand how orientation influences page layout.
Loading demo…
import { Block, Tabs, Text } from '@plocks/ui';
const ORIENTATIONS = ['horizontal', 'vertical'] as const;
const ITEMS = [
{
key: 'general',
label: 'General',
content: <Text>Broad overview content.</Text>
},
{
key: 'security',
label: 'Security',
content: <Text>Security controls and permissions.</Text>
},
{
key: 'notifications',
label: 'Notifications',
content: <Text>Configure alerts and digests.</Text>
}
];
export function Demo() {
return (
<Block fullWidth>
{ORIENTATIONS.map((orientation) => (
<Block key={orientation} fullWidth>
<Text variant="small" c="secondary">{orientation}</Text>
<Tabs orientation={orientation} items={ITEMS} />
</Block>
))}
</Block>
);
}Variants
Compare the
line, chip, and folder visual variants to match tabs with different design aesthetics.Loading demo…
import { Block, Tabs, Text } from '@plocks/ui';
const VARIANTS = ['line', 'chip', 'folder'] as const;
const ITEMS = [
{
key: 'overview',
label: 'Overview',
content: <Text>High-level summary and entry point.</Text>
},
{
key: 'details',
label: 'Details',
content: <Text>Deeper dive into metrics and configuration.</Text>
},
{
key: 'settings',
label: 'Settings',
content: <Text>Manage workspace preferences.</Text>
}
];
export function Demo() {
return (
<Block fullWidth>
{VARIANTS.map((variant) => (
<Block key={variant} fullWidth>
<Text variant="small" c="secondary">{variant}</Text>
<Tabs variant={variant} items={ITEMS} />
</Block>
))}
</Block>
);
}React Native design for iOS, Android, and Web.
Quick Links
Resources