CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-tabs

An accessible and easy tab component for ReactJS with full keyboard navigation and ARIA support

Pending
Overview
Eval results
Files

components.mddocs/

Core Components

Complete set of accessible React components for building tabbed interfaces with keyboard navigation and ARIA compliance.

Core Imports

import { Tabs, TabList, Tab, TabPanel } from "react-tabs";

Capabilities

Tabs Component

Main container component that manages tab state, handles keyboard navigation, and provides controlled/uncontrolled behavior.

/**
 * Main container component for tab functionality
 * Manages state, keyboard navigation, and accessibility
 * @param props - TabsProps configuration object
 * @returns JSX element rendering as div with data-rttabs attribute
 */
const Tabs: React.FunctionComponent<TabsProps>;

interface TabsProps extends Omit<HTMLProps<HTMLDivElement>, 'className' | 'onSelect' | 'ref'> {
  /** CSS class name(s) for the container */
  className?: string | string[] | { [name: string]: boolean };
  /** Focus tabs on initial render */
  defaultFocus?: boolean;
  /** Initial tab index for uncontrolled mode */
  defaultIndex?: number;
  /** Text direction for RTL support */
  direction?: 'rtl' | 'ltr';
  /** CSS class for disabled tabs */
  disabledTabClassName?: string;
  /** Disable up/down arrow key navigation */
  disableUpDownKeys?: boolean;
  /** Disable left/right arrow key navigation */
  disableLeftRightKeys?: boolean;
  /** Ref callback for the root DOM element */
  domRef?: ((node?: HTMLElement) => void);
  /** Window environment for SSR compatibility */
  environment?: Window;
  /** Focus tab when clicked */
  focusTabOnClick?: boolean;
  /** Force render all tab panels */
  forceRenderTabPanel?: boolean;
  /** Selection change callback */
  onSelect?: ((index: number, last: number, event: Event) => boolean | void);
  /** Selected tab index for controlled mode */
  selectedIndex?: number;
  /** CSS class for selected tab */
  selectedTabClassName?: string;
  /** CSS class for selected tab panel */
  selectedTabPanelClassName?: string;
}

Usage Examples:

// Uncontrolled mode with default settings
<Tabs>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
  </TabList>
  <TabPanel>Content 1</TabPanel>
  <TabPanel>Content 2</TabPanel>
</Tabs>

// Controlled mode
const [selectedIndex, setSelectedIndex] = useState(0);

<Tabs 
  selectedIndex={selectedIndex}
  onSelect={(index) => setSelectedIndex(index)}
>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
  </TabList>
  <TabPanel>Content 1</TabPanel>
  <TabPanel>Content 2</TabPanel>
</Tabs>

// With custom styling and initial focus
<Tabs 
  className="my-tabs"
  defaultIndex={1}
  defaultFocus={true}
  selectedTabClassName="active-tab"
>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
  </TabList>
  <TabPanel>Content 1</TabPanel>
  <TabPanel>Content 2</TabPanel>
</Tabs>

TabList Component

Container for Tab components that renders as an accessible <ul> element with role="tablist".

/**
 * Container component for Tab elements
 * Renders as ul element with role="tablist"
 * @param props - TabListProps configuration object
 * @returns JSX element rendering as ul with role="tablist"
 */
const TabList: React.FunctionComponent<TabListProps>;

interface TabListProps extends Omit<HTMLProps<HTMLUListElement>, 'className'> {
  /** CSS class name(s) for the tab list */
  className?: string | string[] | { [name: string]: boolean };
}

Usage Examples:

// Basic tab list
<TabList>
  <Tab>First Tab</Tab>
  <Tab>Second Tab</Tab>
  <Tab>Third Tab</Tab>
</TabList>

// With custom styling
<TabList className="custom-tab-list">
  <Tab>First Tab</Tab>
  <Tab>Second Tab</Tab>
</TabList>

// With multiple class names
<TabList className={["tab-list", "horizontal", { "dark-theme": isDark }]}>
  <Tab>First Tab</Tab>
  <Tab>Second Tab</Tab>
</TabList>

Tab Component

Individual tab elements that render as <li> elements with role="tab" and full ARIA attributes.

/**
 * Individual tab element with accessibility features
 * Renders as li element with role="tab" and ARIA attributes
 * @param props - TabProps configuration object
 * @returns JSX element rendering as li with role="tab"
 */
const Tab: React.FunctionComponent<TabProps>;

interface TabProps extends Omit<HTMLProps<HTMLLIElement>, 'className' | 'tabIndex'> {
  /** CSS class name(s) for the tab */
  className?: string | string[] | { [name: string]: boolean };
  /** Whether the tab is disabled */
  disabled?: boolean;
  /** CSS class for disabled state */
  disabledClassName?: string;
  /** CSS class for selected state */
  selectedClassName?: string;
  /** Tab index for keyboard navigation */
  tabIndex?: string;
}

Usage Examples:

// Basic tabs
<Tab>Home</Tab>
<Tab>About</Tab>
<Tab>Contact</Tab>

// Disabled tab
<Tab disabled>Coming Soon</Tab>

// With custom styling
<Tab 
  className="custom-tab"
  selectedClassName="tab-active"
  disabledClassName="tab-disabled"
>
  Dashboard
</Tab>

// With event handlers
<Tab 
  onClick={handleTabClick}
  onKeyDown={handleKeyDown}
>
  Settings
</Tab>

TabPanel Component

Content areas that render as <div> elements with role="tabpanel" and conditional visibility.

/**
 * Content area for tab panels with conditional rendering
 * Renders as div element with role="tabpanel" and ARIA attributes
 * @param props - TabPanelProps configuration object
 * @returns JSX element rendering as div with role="tabpanel"
 */
const TabPanel: React.FunctionComponent<TabPanelProps>;

interface TabPanelProps extends Omit<HTMLProps<HTMLDivElement>, 'className'> {
  /** CSS class name(s) for the panel */
  className?: string | string[] | { [name: string]: boolean };
  /** Force render even when not selected */
  forceRender?: boolean;
  /** CSS class for selected state */
  selectedClassName?: string;
}

Usage Examples:

// Basic tab panels
<TabPanel>
  <h2>Welcome to our homepage</h2>
  <p>This is the main content area.</p>
</TabPanel>

<TabPanel>
  <h2>About Us</h2>
  <p>Learn more about our company.</p>
</TabPanel>

// Force render panel (keeps content in DOM when not selected)
<TabPanel forceRender={true}>
  <VideoPlayer autoPlay={false} />
</TabPanel>

// With custom styling
<TabPanel 
  className="custom-panel"
  selectedClassName="panel-active"
>
  <ComplexComponent />
</TabPanel>

// With conditional content
<TabPanel>
  {isLoading ? (
    <LoadingSpinner />
  ) : (
    <DataTable data={data} />
  )}
</TabPanel>

Component Relationships

All four components must be used together in the correct hierarchy:

<Tabs>              {/* Root container */}
  <TabList>          {/* Tab navigation */}
    <Tab>Tab 1</Tab> {/* Individual tabs */}
    <Tab>Tab 2</Tab>
  </TabList>
  <TabPanel>         {/* Content panels */}
    Content 1
  </TabPanel>
  <TabPanel>
    Content 2
  </TabPanel>
</Tabs>

Static Properties

Each component includes a tabsRole static property for internal identification:

Tabs.tabsRole = 'Tabs';
TabList.tabsRole = 'TabList';
Tab.tabsRole = 'Tab';
TabPanel.tabsRole = 'TabPanel';

These properties enable the library to validate component structure and ensure proper nesting.

Testing Attributes

React Tabs automatically adds data attributes for testing and internal identification:

/**
 * Data attributes added by the library
 */
interface DataAttributes {
  /** Added to the main Tabs container */
  'data-rttabs': boolean;
  /** Added to each Tab element */  
  'data-rttab': boolean;
}

Testing Usage:

// Jest/Testing Library selectors
const tabsContainer = screen.getByTestId('tabs-container');
// Or using data attributes
const tabsContainer = document.querySelector('[data-rttabs]');
const firstTab = document.querySelector('[data-rttab]');

// Cypress selectors
cy.get('[data-rttabs]').should('exist');
cy.get('[data-rttab]').first().click();

Install with Tessl CLI

npx tessl i tessl/npm-react-tabs

docs

accessibility.md

components.md

index.md

state-management.md

styling.md

tile.json