React tabs UI component providing comprehensive, accessible, and customizable tabbed interfaces
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Extended functionality including extra content, dropdown overflow, custom rendering, and responsive behavior. These features enable sophisticated tab interfaces for complex applications and unique use cases.
Additional content areas within the tab bar for actions, information, or custom controls.
/**
* Extra content configuration for tab bar areas
* Content can be placed on left or right side of tabs
*/
type TabBarExtraContent = React.ReactNode | TabBarExtraMap;
/**
* Map defining content for specific positions in tab bar
*/
type TabBarExtraMap = Partial<Record<TabBarExtraPosition, React.ReactNode>>;
/**
* Available positions for extra content
*/
type TabBarExtraPosition = 'left' | 'right';
/**
* Tab bar styling and layout options
*/
interface TabBarConfig {
/** Extra content in the tab bar */
tabBarExtraContent?: TabBarExtraContent;
/** Gap between individual tabs in pixels */
tabBarGutter?: number;
/** Styles for the tab bar container */
tabBarStyle?: React.CSSProperties;
}Usage Examples:
import Tabs from "rc-tabs";
import { Button, Badge, Avatar } from "antd";
// Simple extra content
function TabsWithExtraContent() {
return (
<Tabs
items={tabItems}
tabBarExtraContent={
<Button type="primary" size="small">
Action
</Button>
}
/>
);
}
// Positioned extra content
function TabsWithPositionedContent() {
return (
<Tabs
items={tabItems}
tabBarExtraContent={{
left: (
<div style={{ marginRight: 16 }}>
<Badge count={5}>
<Avatar icon="user" />
</Badge>
</div>
),
right: (
<div>
<Button size="small" style={{ marginRight: 8 }}>
Save
</Button>
<Button size="small" type="primary">
Publish
</Button>
</div>
),
}}
/>
);
}
// Dynamic extra content
function DynamicExtraContent() {
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
return (
<Tabs
items={tabItems}
tabBarExtraContent={
hasUnsavedChanges ? (
<Badge status="warning" text="Unsaved changes" />
) : (
<Badge status="success" text="All saved" />
)
}
/>
);
}Automatic handling of tab overflow with customizable dropdown for collapsed tabs.
/**
* Configuration for overflow tabs dropdown
*/
interface MoreProps extends Omit<DropdownProps, 'children'> {
/** Custom icon for the more dropdown trigger */
icon?: React.ReactNode;
}
/**
* Dropdown properties from rc-dropdown
* Controls behavior of overflow tabs menu
*/
interface DropdownProps {
/** Dropdown trigger type */
trigger?: Array<'click' | 'hover' | 'contextMenu'>;
/** Dropdown placement */
placement?: 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
/** Whether dropdown is visible */
visible?: boolean;
/** Custom dropdown container */
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
/** Dropdown overlay class name */
overlayClassName?: string;
/** Dropdown overlay style */
overlayStyle?: React.CSSProperties;
}Overflow Examples:
import { MoreOutlined, EllipsisOutlined } from "@ant-design/icons";
// Basic overflow handling
function TabsWithOverflow() {
const manyTabs = Array.from({ length: 20 }, (_, i) => ({
key: `tab-${i + 1}`,
label: `Tab ${i + 1}`,
children: <div>Content for tab {i + 1}</div>,
}));
return (
<Tabs
items={manyTabs}
more={{
icon: <MoreOutlined />,
trigger: ['click'],
}}
/>
);
}
// Custom overflow dropdown
function CustomOverflowTabs() {
return (
<Tabs
items={manyTabs}
more={{
icon: <EllipsisOutlined />,
trigger: ['hover'],
placement: 'bottomRight',
overlayClassName: 'custom-tabs-dropdown',
}}
getPopupContainer={(node) => node.parentElement || document.body}
/>
);
}
// Responsive overflow behavior
function ResponsiveOverflowTabs() {
const [containerWidth, setContainerWidth] = useState(800);
return (
<div style={{ width: containerWidth }}>
<input
type="range"
min="300"
max="1200"
value={containerWidth}
onChange={(e) => setContainerWidth(Number(e.target.value))}
/>
<Tabs
items={manyTabs}
more={{
icon: <span>···</span>,
}}
/>
</div>
);
}Complete customization of tab bar appearance and behavior through render functions.
/**
* Custom tab bar render function
* Provides complete control over tab bar rendering
*/
type RenderTabBar = (
props: RenderTabBarProps,
DefaultTabBar: React.ComponentType<TabNavListProps>
) => React.ReactElement;
/**
* Properties passed to custom tab bar render function
*/
interface RenderTabBarProps {
id: string;
activeKey: string;
animated: AnimatedConfig;
tabPosition: TabPosition;
rtl: boolean;
mobile: boolean;
editable: EditableConfig;
locale: TabsLocale;
more: MoreProps;
tabBarGutter: number;
onTabClick: (key: string, e: React.MouseEvent | React.KeyboardEvent) => void;
onTabScroll: OnTabScroll;
extra: TabBarExtraContent;
style: React.CSSProperties;
}
/**
* Default tab bar component props
*/
interface TabNavListProps {
id: string;
tabPosition: TabPosition;
activeKey: string;
rtl: boolean;
animated?: AnimatedConfig;
extra?: TabBarExtraContent;
editable?: EditableConfig;
more?: MoreProps;
mobile: boolean;
tabBarGutter?: number;
className?: string;
style?: React.CSSProperties;
locale?: TabsLocale;
onTabClick: (activeKey: string, e: React.MouseEvent | React.KeyboardEvent) => void;
onTabScroll?: OnTabScroll;
}Custom Rendering Examples:
// Wrapped tab bar with additional controls
function TabsWithCustomBar() {
const renderTabBar = (props: RenderTabBarProps, DefaultTabBar: any) => (
<div className="custom-tab-bar-wrapper">
<div className="tab-bar-header">
<h3>Document Tabs</h3>
<Button size="small">Settings</Button>
</div>
<DefaultTabBar {...props} />
</div>
);
return (
<Tabs
items={tabItems}
renderTabBar={renderTabBar}
/>
);
}
// Completely custom tab bar
function TabsWithFullCustomBar() {
const [activeKey, setActiveKey] = useState('1');
const renderTabBar = (props: RenderTabBarProps) => (
<div className="custom-tabs-nav">
{tabItems.map(item => (
<button
key={item.key}
className={`custom-tab ${activeKey === item.key ? 'active' : ''}`}
onClick={(e) => {
setActiveKey(item.key);
props.onTabClick(item.key, e);
}}
>
{item.label}
{activeKey === item.key && <span className="active-indicator" />}
</button>
))}
</div>
);
return (
<Tabs
activeKey={activeKey}
items={tabItems}
renderTabBar={renderTabBar}
/>
);
}
// Conditional tab bar rendering
function ConditionalTabBar() {
const [isCompact, setIsCompact] = useState(false);
const renderTabBar = (props: RenderTabBarProps, DefaultTabBar: any) => {
if (isCompact) {
return (
<select
value={props.activeKey}
onChange={(e) => props.onTabClick(e.target.value, e as any)}
>
{tabItems.map(item => (
<option key={item.key} value={item.key}>
{item.label}
</option>
))}
</select>
);
}
return <DefaultTabBar {...props} />;
};
return (
<Tabs
items={tabItems}
renderTabBar={renderTabBar}
/>
);
}Control and respond to tab scrolling behavior in overflow scenarios.
/**
* Tab scroll event handler
* Fired when tab bar is scrolled horizontally or vertically
*/
type OnTabScroll = (info: { direction: 'left' | 'right' | 'top' | 'bottom' }) => void;
/**
* Scroll behavior configuration
*/
interface TabScrollConfig {
/** Callback for tab scroll events */
onTabScroll?: OnTabScroll;
/** Whether to show scroll buttons in overflow */
showScrollArrows?: boolean;
/** Scroll speed and behavior settings */
scrollAnimated?: boolean;
}Scroll Examples:
// Tab scroll monitoring
function ScrollMonitoredTabs() {
const [scrollInfo, setScrollInfo] = useState('');
const handleTabScroll = (info: { direction: string }) => {
setScrollInfo(`Scrolled ${info.direction} at ${new Date().toLocaleTimeString()}`);
};
return (
<div>
<div>Scroll Status: {scrollInfo}</div>
<Tabs
items={manyTabs}
onTabScroll={handleTabScroll}
/>
</div>
);
}
// Programmatic tab scrolling
function ProgrammaticScrollTabs() {
const tabsRef = useRef<HTMLDivElement>(null);
const scrollToTab = (direction: 'left' | 'right') => {
const tabsElement = tabsRef.current?.querySelector('.rc-tabs-nav-wrap');
if (tabsElement) {
const scrollAmount = 200;
tabsElement.scrollBy({
left: direction === 'left' ? -scrollAmount : scrollAmount,
behavior: 'smooth',
});
}
};
return (
<div>
<div>
<Button onClick={() => scrollToTab('left')}>← Scroll Left</Button>
<Button onClick={() => scrollToTab('right')}>Scroll Right →</Button>
</div>
<Tabs
ref={tabsRef}
items={manyTabs}
/>
</div>
);
}Customization of the tab indicator (ink bar) appearance and behavior.
/**
* Tab indicator configuration
* Controls the visual indicator showing active tab
*/
interface IndicatorConfig {
/** Function to calculate indicator size */
size?: GetIndicatorSize;
/** Alignment of indicator relative to tab */
align?: 'start' | 'center' | 'end';
}
/**
* Type for calculating indicator size
* Can be a number or function that takes origin size and returns new size
*/
type GetIndicatorSize = number | ((origin: number) => number);Indicator Examples:
// Fixed size indicator
function FixedSizeIndicatorTabs() {
return (
<Tabs
items={tabItems}
indicator={{
size: 3, // Fixed 3px indicator height/width
align: 'center',
}}
/>
);
}
// Dynamic indicator sizing
function DynamicIndicatorTabs() {
const calculateSize: GetIndicatorSize = (originalSize) => {
// Make indicator 80% of original size
return Math.floor(originalSize * 0.8);
};
return (
<Tabs
items={tabItems}
indicator={{
size: calculateSize,
align: 'center',
}}
/>
);
}
// Responsive indicator based on screen size
function ResponsiveIndicatorTabs() {
const [indicatorSize, setIndicatorSize] = useState<GetIndicatorSize>(2);
useEffect(() => {
const updateSize = () => {
setIndicatorSize(window.innerWidth < 768 ? 2 : 4);
};
updateSize();
window.addEventListener('resize', updateSize);
return () => window.removeEventListener('resize', updateSize);
}, []);
return (
<Tabs
items={tabItems}
indicator={{
size: indicatorSize,
align: 'start',
}}
/>
);
}Control where popups and dropdowns are rendered for proper z-index and positioning.
/**
* Popup container configuration
* Controls where dropdown and popup elements are rendered
*/
interface PopupConfig {
/** Function to get container element for popups */
getPopupContainer?: (node: HTMLElement) => HTMLElement;
/** CSS class name for popup elements */
popupClassName?: string;
}Popup Container Examples:
// Custom popup container
function CustomPopupTabs() {
return (
<div className="tabs-container">
<Tabs
items={manyTabs}
getPopupContainer={(node) => {
// Render popups in specific container
return document.querySelector('.popup-container') || document.body;
}}
popupClassName="custom-tabs-popup"
more={{
icon: <MoreOutlined />,
}}
/>
<div className="popup-container" />
</div>
);
}
// Modal-safe popup rendering
function ModalSafeTabs({ inModal }: { inModal: boolean }) {
return (
<Tabs
items={manyTabs}
getPopupContainer={inModal ?
(node) => node.closest('.ant-modal-content') || document.body :
undefined
}
more={{
icon: <MoreOutlined />,
}}
/>
);
}Install with Tessl CLI
npx tessl i tessl/npm-rc-tabs