# SegmentedTabs **📖 Live documentation:** https://cds.coinbase.com/components/navigation/SegmentedTabs/ Switches between different views of content. ## Import ```tsx import { SegmentedTabs } from '@coinbase/cds-web/tabs/SegmentedTabs' ``` ## Examples SegmentedTabs is a controlled component that uses `activeTab` and `onChange` to manage selection state. ### Basics #### Initial Value You can set any tab as the initial active tab by passing it to the `activeTab` state. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` SegmentedTabs can also start with no active selection by passing `null`. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(null); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` #### Disabled The entire component can be disabled with the `disabled` prop. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` Individual tabs can also be disabled while keeping others interactive. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell', disabled: true }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` ### Styling #### Border Radius Set `borderRadius` to change the shape of both the container and the active indicator. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` Use the `styles` prop to set a different `borderRadius` on the active indicator than the outer container, with `padding` to create an inset effect. ```jsx live function Example() { const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` #### Labels Labels can be customized with any `ReactNode`, including instances of `Icon`. ```jsx live function Example() { const tabs = [ { id: 'buy', label: }, { id: 'sell', label: }, { id: 'convert', label: }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` ### Custom Components Use `TabComponent` and `TabsActiveIndicatorComponent` to fully customize the tabs and active indicator. Individual tabs can also be customized by providing a `Component` in the tab definition. ```jsx live function Example() { const CustomActiveIndicator = useCallback( ({ activeTabRect }) => ( ), [], ); const CustomTab = useCallback(({ id, label, disabled }) => { const { activeTab } = useTabsContext(); const isActive = activeTab?.id === id; const renderedLabel = ( {label} ); return ( ); }, []); const tabs = [ { id: 'buy', label: 'Buy' }, { id: 'sell', label: 'Sell' }, { id: 'convert', label: 'Convert' }, ]; const [activeTab, updateActiveTab] = useState(tabs[0]); const handleChange = useCallback((activeTab) => updateActiveTab(activeTab), []); return ( ); } ``` ## Props | Prop | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `activeTab` | `TabValue \| null` | Yes | `-` | React state for the currently active tab. Setting it to null results in no active tab. | | `onChange` | `(activeTab: TabValue \| null) => void` | Yes | `-` | Callback that is fired when the active tab changes. Use this callback to update the activeTab state. | | `tabs` | `(TabValue & { Component?: TabComponent> \| undefined; })[]` | Yes | `-` | The array of tabs data. Each tab may optionally define a custom Component to render. | | `TabComponent` | `TabComponent>` | No | `-` | The default Component to render each tab. | | `TabsActiveIndicatorComponent` | `TabsActiveIndicatorComponent` | No | `-` | The default Component to render the tabs active indicator. | | `activeBackground` | `Color` | No | `-` | Background color passed to the TabsActiveIndicatorComponent. | | `alignContent` | `ResponsiveProp
` | No | `-` | - | | `alignItems` | `ResponsiveProp
` | No | `-` | - | | `alignSelf` | `ResponsiveProp
` | No | `-` | - | | `as` | `div` | No | `-` | The underlying element or component the polymorphic component will render. Changing as also changes the inherited native props (e.g. href for as=a) and the expected ref type. | | `aspectRatio` | `ResponsiveProp` | No | `-` | - | | `background` | `ResponsiveProp` | No | `-` | - | | `borderBottomLeftRadius` | `ResponsiveProp` | No | `-` | - | | `borderBottomRightRadius` | `ResponsiveProp` | No | `-` | - | | `borderBottomWidth` | `ResponsiveProp` | No | `-` | - | | `borderColor` | `ResponsiveProp` | No | `-` | - | | `borderEndWidth` | `ResponsiveProp` | No | `-` | - | | `borderRadius` | `ResponsiveProp` | No | `-` | - | | `borderStartWidth` | `ResponsiveProp` | No | `-` | - | | `borderTopLeftRadius` | `ResponsiveProp` | No | `-` | - | | `borderTopRightRadius` | `ResponsiveProp` | No | `-` | - | | `borderTopWidth` | `ResponsiveProp` | No | `-` | - | | `borderWidth` | `ResponsiveProp` | No | `-` | - | | `bordered` | `boolean` | No | `-` | Add a border around all sides of the box. | | `borderedBottom` | `boolean` | No | `-` | Add a border to the bottom side of the box. | | `borderedEnd` | `boolean` | No | `-` | Add a border to the trailing side of the box. | | `borderedHorizontal` | `boolean` | No | `-` | Add a border to the leading and trailing sides of the box. | | `borderedStart` | `boolean` | No | `-` | Add a border to the leading side of the box. | | `borderedTop` | `boolean` | No | `-` | Add a border to the top side of the box. | | `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. | | `bottom` | `ResponsiveProp>` | No | `-` | - | | `classNames` | `{ root?: string; tab?: string \| undefined; activeIndicator?: string \| undefined; } \| undefined` | No | `-` | Custom class names for individual elements of the SegmentedTabs component | | `color` | `ResponsiveProp` | No | `-` | - | | `columnGap` | `ResponsiveProp` | No | `-` | - | | `dangerouslySetBackground` | `string` | No | `-` | - | | `disabled` | `boolean` | No | `-` | Disable interactions on all the tabs. | | `display` | `ResponsiveProp` | No | `-` | - | | `elevation` | `ResponsiveProp` | No | `-` | - | | `flexBasis` | `ResponsiveProp>` | No | `-` | - | | `flexDirection` | `ResponsiveProp` | No | `-` | - | | `flexGrow` | `ResponsiveProp` | No | `-` | - | | `flexShrink` | `ResponsiveProp` | No | `-` | - | | `flexWrap` | `ResponsiveProp` | No | `-` | - | | `font` | `ResponsiveProp` | No | `-` | - | | `fontFamily` | `ResponsiveProp` | No | `-` | - | | `fontSize` | `ResponsiveProp` | No | `-` | - | | `fontWeight` | `ResponsiveProp` | No | `-` | - | | `gap` | `ResponsiveProp` | No | `-` | - | | `grid` | `ResponsiveProp` | No | `-` | - | | `gridArea` | `ResponsiveProp` | No | `-` | - | | `gridAutoColumns` | `ResponsiveProp>` | No | `-` | - | | `gridAutoFlow` | `ResponsiveProp` | No | `-` | - | | `gridAutoRows` | `ResponsiveProp>` | No | `-` | - | | `gridColumn` | `ResponsiveProp` | No | `-` | - | | `gridColumnEnd` | `ResponsiveProp` | No | `-` | - | | `gridColumnStart` | `ResponsiveProp` | No | `-` | - | | `gridRow` | `ResponsiveProp` | No | `-` | - | | `gridRowEnd` | `ResponsiveProp` | No | `-` | - | | `gridRowStart` | `ResponsiveProp` | No | `-` | - | | `gridTemplate` | `ResponsiveProp` | No | `-` | - | | `gridTemplateAreas` | `ResponsiveProp` | No | `-` | - | | `gridTemplateColumns` | `ResponsiveProp>` | No | `-` | - | | `gridTemplateRows` | `ResponsiveProp>` | No | `-` | - | | `height` | `ResponsiveProp>` | No | `-` | - | | `justifyContent` | `ResponsiveProp` | No | `-` | - | | `key` | `Key \| null` | No | `-` | - | | `left` | `ResponsiveProp>` | No | `-` | - | | `lineHeight` | `ResponsiveProp` | No | `-` | - | | `margin` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginBottom` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginEnd` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginStart` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginTop` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginX` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginY` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `maxHeight` | `ResponsiveProp>` | No | `-` | - | | `maxWidth` | `ResponsiveProp>` | No | `-` | - | | `minHeight` | `ResponsiveProp>` | No | `-` | - | | `minWidth` | `ResponsiveProp>` | No | `-` | - | | `onActiveTabElementChange` | `((element: HTMLElement \| null) => void)` | No | `-` | Optional callback to receive the active tab element. | | `opacity` | `ResponsiveProp` | No | `-` | - | | `overflow` | `ResponsiveProp` | No | `-` | - | | `padding` | `ResponsiveProp` | No | `-` | - | | `paddingBottom` | `ResponsiveProp` | No | `-` | - | | `paddingEnd` | `ResponsiveProp` | No | `-` | - | | `paddingStart` | `ResponsiveProp` | No | `-` | - | | `paddingTop` | `ResponsiveProp` | No | `-` | - | | `paddingX` | `ResponsiveProp` | No | `-` | - | | `paddingY` | `ResponsiveProp` | No | `-` | - | | `pin` | `PinningDirection` | No | `-` | Direction in which to absolutely pin the box. | | `position` | `ResponsiveProp` | No | `-` | - | | `ref` | `ForwardedRef` | No | `-` | - | | `right` | `ResponsiveProp>` | No | `-` | - | | `rowGap` | `ResponsiveProp` | No | `-` | - | | `style` | `CSSProperties` | No | `-` | - | | `styles` | `{ root?: CSSProperties; tab?: CSSProperties \| undefined; activeIndicator?: CSSProperties \| undefined; } \| undefined` | No | `-` | Custom styles for individual elements of the SegmentedTabs component | | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID | | `textAlign` | `ResponsiveProp
` | No | `-` | - | | `textDecoration` | `ResponsiveProp` | No | `-` | - | | `textTransform` | `ResponsiveProp` | No | `-` | - | | `top` | `ResponsiveProp>` | No | `-` | - | | `transform` | `ResponsiveProp` | No | `-` | - | | `userSelect` | `ResponsiveProp` | No | `-` | - | | `visibility` | `ResponsiveProp` | No | `-` | - | | `width` | `ResponsiveProp>` | No | `-` | - | | `zIndex` | `ResponsiveProp` | No | `-` | - | ## Styles | Selector | Static class name | Description | | --- | --- | --- | | `root` | `-` | Root element | | `tab` | `-` | Tab element | | `activeIndicator` | `-` | Active indicator element |