Skip to content

useTabs

Edit on GitHub
@volvo-cars/react-headless v0.24.7

A collection of hooks for building accessible tab interfaces (MDN tabs pattern).

The tabs system consists of three hooks that work together:

  • useTabList – manages the tab list state and keyboard navigation
  • useTab – provides props for individual tab elements
  • useTabPanel – provides props for tab panel elements
import { useTabList, useTab, useTabPanel } from '@volvo-cars/react-headless';
function Tabs() {
const { tabListProps, tabGroupState } = useTabList();
return (
<div>
<div {...tabListProps}>
<Tab state={tabGroupState} index={0}>
First
</Tab>
<Tab state={tabGroupState} index={1}>
Second
</Tab>
<Tab state={tabGroupState} index={2}>
Third
</Tab>
</div>
<TabPanel state={tabGroupState} index={0}>
First panel content
</TabPanel>
<TabPanel state={tabGroupState} index={1}>
Second panel content
</TabPanel>
<TabPanel state={tabGroupState} index={2}>
Third panel content
</TabPanel>
</div>
);
}
function Tab({ state, index, children }) {
const { tabProps } = useTab({ state, index });
return <button {...tabProps}>{children}</button>;
}
function TabPanel({ state, index, children }) {
const { tabPanelProps, isSelected } = useTabPanel({ state, index });
if (!isSelected) return null;
return <div {...tabPanelProps}>{children}</div>;
}

Control the selected tab externally:

import { useState } from 'react';
import { useTabList, useTab, useTabPanel } from '@volvo-cars/react-headless';
function ControlledTabs() {
const [selectedIndex, setSelectedIndex] = useState(0);
const { tabListProps, tabGroupState } = useTabList({
selectedIndex,
onChange: setSelectedIndex,
});
return (
<div>
<div {...tabListProps}>
<Tab state={tabGroupState} index={0}>
First
</Tab>
<Tab state={tabGroupState} index={1}>
Second
</Tab>
</div>
<TabPanel state={tabGroupState} index={0}>
First panel
</TabPanel>
<TabPanel state={tabGroupState} index={1}>
Second panel
</TabPanel>
</div>
);
}

Set orientation to 'vertical' for vertical tab lists. Arrow Up/Down will navigate instead of Left/Right:

import { useTabList } from '@volvo-cars/react-headless';
function VerticalTabs() {
const { tabListProps, tabGroupState } = useTabList({
orientation: 'vertical',
});
return (
<div className="flex">
<div {...tabListProps} className="flex flex-col">
{/* tabs */}
</div>
<div>{/* panels */}</div>
</div>
);
}

useTabList accepts an optional options object:

  • id – custom id for the tab list (auto-generated if not provided)
  • selectedIndex – controlled selected tab index
  • defaultSelectedIndex – initial selected tab for uncontrolled usage (default: 0)
  • orientation'horizontal' or 'vertical' for keyboard navigation
  • onChange – callback fired when the selected tab changes

Returns:

  • selectedIndex – the currently selected tab index
  • tabListProps – props to spread on the tab list container
  • tabGroupState – state object to pass to useTab and useTabPanel

useTab accepts an options object:

  • state – the tabGroupState from useTabList
  • index – the index of this tab

Returns:

  • isSelected – whether this tab is selected
  • tabProps – props to spread on the tab element

useTabPanel accepts an options object:

  • state – the tabGroupState from useTabList
  • index – the index of this panel

Returns:

  • isSelected – whether this panel’s tab is selected
  • tabPanelProps – props to spread on the panel element