Tabs
Tabs is a flexible, accessible tab navigation component for switching between content sections. It supports custom tab components, animated active indicators, and full keyboard navigation.@coinbase/cds-web@8.56.1
import { Tabs } from '@coinbase/cds-web/tabs/Tabs'
Peer dependencies
- framer-motion: ^10.18.0
Related components
Tabs is a low-level primitive for building custom tab interfaces. It requires a TabComponent and TabsActiveIndicatorComponent to render. For a ready-to-use tab experience, see SegmentedTabs.
Basics
Initial Value
Use useTabsContext inside your TabComponent to access the active tab state. Pair with TabLabel for consistent label styling and TabsActiveIndicator for the animated indicator.
Loading...
Live Codefunction Example() { const tabs = [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3' }, ]; const TabComponent = useCallback(({ id, label, disabled, ...props }) => { const { activeTab, updateActiveTab } = useTabsContext(); const isActive = activeTab?.id === id; return ( <Pressable onClick={() => updateActiveTab(id)} disabled={disabled} aria-pressed={isActive} {...props} > <TabLabel id={id} active={isActive}> {label} </TabLabel> </Pressable> ); }, []); const ActiveIndicator = useCallback( (props) => <TabsActiveIndicator {...props} background="bgPrimary" bottom={0} height={2} />, [], ); const [activeTab, setActiveTab] = useState(tabs[0]); return ( <Tabs gap={4} tabs={tabs} activeTab={activeTab} onChange={setActiveTab} TabComponent={TabComponent} TabsActiveIndicatorComponent={ActiveIndicator} /> ); }
Tabs can also start with no active selection by passing null.
Loading...
Live Codefunction Example() { const tabs = [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3' }, ]; const TabComponent = useCallback(({ id, label, disabled, ...props }) => { const { activeTab, updateActiveTab } = useTabsContext(); const isActive = activeTab?.id === id; return ( <Pressable onClick={() => updateActiveTab(id)} disabled={disabled} aria-pressed={isActive} {...props} > <TabLabel id={id} active={isActive}> {label} </TabLabel> </Pressable> ); }, []); const ActiveIndicator = useCallback( (props) => <TabsActiveIndicator {...props} background="bgPrimary" bottom={0} height={2} />, [], ); const [activeTab, setActiveTab] = useState(null); return ( <Tabs gap={4} tabs={tabs} activeTab={activeTab} onChange={setActiveTab} TabComponent={TabComponent} TabsActiveIndicatorComponent={ActiveIndicator} /> ); }
Disabled
The entire component can be disabled with the disabled prop.
Loading...
Live Codefunction Example() { const tabs = [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3' }, ]; const TabComponent = useCallback(({ id, label, disabled, ...props }) => { const { activeTab, updateActiveTab } = useTabsContext(); const isActive = activeTab?.id === id; return ( <Pressable onClick={() => updateActiveTab(id)} disabled={disabled} aria-pressed={isActive} {...props} > <TabLabel id={id} active={isActive}> {label} </TabLabel> </Pressable> ); }, []); const ActiveIndicator = useCallback( (props) => <TabsActiveIndicator {...props} background="bgPrimary" bottom={0} height={2} />, [], ); const [activeTab, setActiveTab] = useState(tabs[0]); return ( <Tabs disabled gap={4} tabs={tabs} activeTab={activeTab} onChange={setActiveTab} TabComponent={TabComponent} TabsActiveIndicatorComponent={ActiveIndicator} /> ); }