An accessible and easy tab component for ReactJS with full keyboard navigation and ARIA support
—
Flexible styling system supporting multiple className formats, default CSS classes, and comprehensive customization options.
import { Tabs, TabList, Tab, TabPanel } from "react-tabs";
import "react-tabs/style/react-tabs.css"; // Default stylesComplete set of default CSS classes for immediate styling without configuration.
/**
* Default CSS classes applied automatically
*/
interface DefaultCSSClasses {
/** Main container class */
'react-tabs': string;
/** Tab list container class */
'react-tabs__tab-list': string;
/** Individual tab class */
'react-tabs__tab': string;
/** Selected tab modifier */
'react-tabs__tab--selected': string;
/** Disabled tab modifier */
'react-tabs__tab--disabled': string;
/** Tab panel class */
'react-tabs__tab-panel': string;
/** Selected panel modifier */
'react-tabs__tab-panel--selected': string;
}Default Styles Usage:
// Import default CSS
import "react-tabs/style/react-tabs.css";
// Basic usage gets default styling
<Tabs>
<TabList>
<Tab>Tab 1</Tab>
<Tab>Tab 2</Tab>
</TabList>
<TabPanel>Content 1</TabPanel>
<TabPanel>Content 2</TabPanel>
</Tabs>Default CSS Structure:
.react-tabs {
-webkit-tap-highlight-color: transparent;
}
.react-tabs__tab-list {
border-bottom: 1px solid #aaa;
margin: 0 0 10px;
padding: 0;
}
.react-tabs__tab {
display: inline-block;
border: 1px solid transparent;
border-bottom: none;
bottom: -1px;
position: relative;
list-style: none;
padding: 6px 12px;
cursor: pointer;
}
.react-tabs__tab--selected {
background: #fff;
border-color: #aaa;
color: black;
border-radius: 5px 5px 0 0;
}
.react-tabs__tab--disabled {
color: GrayText;
cursor: default;
}
.react-tabs__tab:focus {
outline: none;
}
.react-tabs__tab:focus:after {
content: '';
position: absolute;
height: 5px;
left: -4px;
right: -4px;
bottom: -5px;
background: #fff;
}
.react-tabs__tab-panel {
display: none;
}
.react-tabs__tab-panel--selected {
display: block;
}Support for multiple className formats including strings, arrays, and objects using clsx library.
/**
* Flexible className type supporting multiple formats
*/
type ClassNameProp = string | string[] | { [name: string]: boolean };
interface StyleProps {
/** Main container class names */
className?: ClassNameProp;
}
/**
* Examples of valid className values:
* - "my-tabs" (string)
* - ["my-tabs", "horizontal"] (array)
* - { "my-tabs": true, "dark": isDark } (object)
* - ["my-tabs", { "dark": isDark }] (mixed)
*/ClassName Format Examples:
// String format
<Tabs className="my-custom-tabs">
<TabList className="my-tab-list">
<Tab className="my-tab">Tab 1</Tab>
<Tab className="my-tab">Tab 2</Tab>
</TabList>
<TabPanel className="my-panel">Content 1</TabPanel>
<TabPanel className="my-panel">Content 2</TabPanel>
</Tabs>
// Array format
<Tabs className={["tabs", "horizontal", "shadow"]}>
<TabList className={["tab-list", "nav"]}>
<Tab className={["tab", "nav-item"]}>Tab 1</Tab>
</TabList>
<TabPanel className={["panel", "content"]}>Content 1</TabPanel>
</Tabs>
// Object format (conditional classes)
<Tabs className={{
"tabs": true,
"tabs--dark": isDarkMode,
"tabs--vertical": isVertical
}}>
<TabList className={{
"tab-list": true,
"tab-list--compact": isCompact
}}>
<Tab className={{
"tab": true,
"tab--active": isActive,
"tab--disabled": isDisabled
}}>
Tab 1
</Tab>
</TabList>
</Tabs>
// Mixed array and object format
<Tabs className={[
"tabs",
"tabs--primary",
{ "tabs--loading": isLoading }
]}>
{/* components */}
</Tabs>Dedicated className props for different component states with automatic application.
interface TabsStyleProps {
/** CSS class for selected tabs */
selectedTabClassName?: string;
/** CSS class for selected panels */
selectedTabPanelClassName?: string;
/** CSS class for disabled tabs */
disabledTabClassName?: string;
}
interface TabStyleProps {
/** CSS class when tab is selected */
selectedClassName?: string;
/** CSS class when tab is disabled */
disabledClassName?: string;
}
interface TabPanelStyleProps {
/** CSS class when panel is selected */
selectedClassName?: string;
}State-Specific Styling Examples:
// Global state classes on Tabs component
<Tabs
selectedTabClassName="tab-active"
selectedTabPanelClassName="panel-active"
disabledTabClassName="tab-disabled"
>
<TabList>
<Tab>Active Tab</Tab>
<Tab disabled>Disabled Tab</Tab>
</TabList>
<TabPanel>Active Panel</TabPanel>
<TabPanel>Panel 2</TabPanel>
</Tabs>
// Individual component state classes
<Tabs>
<TabList>
<Tab
selectedClassName="my-selected-tab"
disabledClassName="my-disabled-tab"
>
Tab 1
</Tab>
<Tab>Tab 2</Tab>
</TabList>
<TabPanel selectedClassName="my-active-panel">
Content 1
</TabPanel>
<TabPanel>Content 2</TabPanel>
</Tabs>
// CSS-in-JS with dynamic classes
const tabStyles = {
selected: 'bg-blue-500 text-white',
default: 'bg-gray-200 text-gray-700',
disabled: 'bg-gray-100 text-gray-400 cursor-not-allowed'
};
<Tabs
selectedTabClassName={tabStyles.selected}
disabledTabClassName={tabStyles.disabled}
>
<TabList>
<Tab className={tabStyles.default}>Tab 1</Tab>
<Tab className={tabStyles.default} disabled>Tab 2</Tab>
</TabList>
<TabPanel>Content 1</TabPanel>
<TabPanel>Content 2</TabPanel>
</Tabs>Advanced styling patterns for different design systems and frameworks.
CSS Modules Pattern:
import styles from './Tabs.module.css';
<Tabs className={styles.tabs}>
<TabList className={styles.tabList}>
<Tab className={styles.tab}>Tab 1</Tab>
<Tab className={styles.tab}>Tab 2</Tab>
</TabList>
<TabPanel className={styles.panel}>Content 1</TabPanel>
<TabPanel className={styles.panel}>Content 2</TabPanel>
</Tabs>Styled Components Pattern:
import styled from 'styled-components';
const StyledTabs = styled(Tabs)`
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
`;
const StyledTabList = styled(TabList)`
border-bottom: 2px solid #e1e5e9;
margin-bottom: 16px;
`;
const StyledTab = styled(Tab)`
padding: 12px 24px;
cursor: pointer;
border: none;
background: transparent;
&.react-tabs__tab--selected {
border-bottom: 2px solid #007bff;
color: #007bff;
}
`;
<StyledTabs>
<StyledTabList>
<StyledTab>Tab 1</StyledTab>
<StyledTab>Tab 2</StyledTab>
</StyledTabList>
<TabPanel>Content 1</TabPanel>
<TabPanel>Content 2</TabPanel>
</StyledTabs>Tailwind CSS Pattern:
<Tabs className="bg-white rounded-lg shadow-lg">
<TabList className="flex border-b border-gray-200">
<Tab className="px-6 py-3 text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300">
Tab 1
</Tab>
<Tab className="ml-8 px-6 py-3 text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300">
Tab 2
</Tab>
</TabList>
<TabPanel className="p-6">
<div className="text-gray-900">Content 1</div>
</TabPanel>
<TabPanel className="p-6">
<div className="text-gray-900">Content 2</div>
</TabPanel>
</Tabs>Integration patterns with popular theming systems and design libraries.
Material-UI Integration:
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
tabs: {
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadius,
},
tabList: {
borderBottom: `1px solid ${theme.palette.divider}`,
},
tab: {
padding: theme.spacing(1, 2),
minHeight: theme.spacing(6),
'&.react-tabs__tab--selected': {
color: theme.palette.primary.main,
borderBottomColor: theme.palette.primary.main,
},
},
}));
function MaterialTabs() {
const classes = useStyles();
return (
<Tabs className={classes.tabs}>
<TabList className={classes.tabList}>
<Tab className={classes.tab}>Tab 1</Tab>
<Tab className={classes.tab}>Tab 2</Tab>
</TabList>
<TabPanel>Content 1</TabPanel>
<TabPanel>Content 2</TabPanel>
</Tabs>
);
}Chakra UI Integration:
import { Box, useColorModeValue } from '@chakra-ui/react';
function ChakraTabs() {
const bg = useColorModeValue('white', 'gray.800');
const borderColor = useColorModeValue('gray.200', 'gray.600');
return (
<Tabs className="chakra-tabs">
<TabList
className="chakra-tab-list"
style={{
background: bg,
borderBottom: `1px solid ${borderColor}`
}}
>
<Tab>Tab 1</Tab>
<Tab>Tab 2</Tab>
</TabList>
<TabPanel>
<Box p={4}>Content 1</Box>
</TabPanel>
<TabPanel>
<Box p={4}>Content 2</Box>
</TabPanel>
</Tabs>
);
}Responsive design patterns for mobile and tablet compatibility.
// Responsive breakpoint classes
<Tabs className="tabs-responsive">
<TabList className="tab-list-mobile sm:tab-list-desktop">
<Tab className="tab-mobile sm:tab-desktop">Tab 1</Tab>
<Tab className="tab-mobile sm:tab-desktop">Tab 2</Tab>
</TabList>
<TabPanel className="panel-mobile sm:panel-desktop">
Content 1
</TabPanel>
<TabPanel className="panel-mobile sm:panel-desktop">
Content 2
</TabPanel>
</Tabs>Responsive CSS Example:
.tabs-responsive {
width: 100%;
}
.tab-list-mobile {
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.tab-mobile {
flex-shrink: 0;
padding: 8px 12px;
font-size: 14px;
}
@media (min-width: 640px) {
.tab-list-desktop {
overflow-x: visible;
}
.tab-desktop {
padding: 12px 24px;
font-size: 16px;
}
}
.panel-mobile {
padding: 16px;
}
@media (min-width: 640px) {
.panel-desktop {
padding: 24px;
}
}CSS transition and animation integration for smooth tab switching.
// CSS transitions
<Tabs className="animated-tabs">
<TabList className="animated-tab-list">
<Tab className="animated-tab">Tab 1</Tab>
<Tab className="animated-tab">Tab 2</Tab>
</TabList>
<TabPanel className="animated-panel">Content 1</TabPanel>
<TabPanel className="animated-panel">Content 2</TabPanel>
</Tabs>Animation CSS Example:
.animated-tab {
transition: all 0.3s ease;
opacity: 0.7;
transform: translateY(2px);
}
.animated-tab.react-tabs__tab--selected {
opacity: 1;
transform: translateY(0);
}
.animated-panel {
opacity: 0;
transform: translateX(10px);
animation: slideIn 0.3s ease forwards;
}
.animated-panel.react-tabs__tab-panel--selected {
opacity: 1;
transform: translateX(0);
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}Install with Tessl CLI
npx tessl i tessl/npm-react-tabs