import { SidebarMoreMenu } from '@coinbase/cds-web/navigation/SidebarMoreMenu'
SidebarMoreMenu wraps a Dropdown to provide an overflow menu for additional navigation items in a Sidebar. Use it when you have more navigation items than can fit in the visible sidebar area.
Basics
Place SidebarMoreMenu inside a Sidebar component. Pass SelectOption components as children to define the menu items. Use the onChange callback to handle selection and value to control the selected item.
function BasicSidebarMoreMenu() { const [activeIndex, setActiveIndex] = useState(0); const [moreMenuValue, setMoreMenuValue] = useState(); const mainItems = [ { title: 'Home', icon: 'home' }, { title: 'Assets', icon: 'chartPie' }, { title: 'Trade', icon: 'trading' }, ]; const moreItems = [ { title: 'Rewards', icon: 'giftBox' }, { title: 'Lending', icon: 'cash' }, { title: 'DeFi', icon: 'defi' }, ]; const handleMoreMenuChange = (newValue) => { const moreIndex = moreItems.findIndex((item) => item.title === newValue) + mainItems.length; setActiveIndex(moreIndex); setMoreMenuValue(newValue); }; const handleItemClick = (index) => { setActiveIndex(index); setMoreMenuValue(undefined); }; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden"> <Sidebar logo={<LogoMark />}> {mainItems.map((item, index) => ( <SidebarItem key={item.title} active={index === activeIndex} icon={item.icon} onClick={() => handleItemClick(index)} title={item.title} tooltipContent={item.title} /> ))} <SidebarMoreMenu active={activeIndex >= mainItems.length} onChange={handleMoreMenuChange} tooltipContent="More" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }
Trigger Title
Use triggerTitle to customize the label shown on the menu trigger. This is useful for localization.
function TriggerTitleExample() { const [moreMenuValue, setMoreMenuValue] = useState(); const moreItems = [ { title: 'Settings', icon: 'cog' }, { title: 'Help', icon: 'questionCircle' }, ]; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden"> <Sidebar logo={<LogoMark />}> <SidebarItem icon="home" title="Home" tooltipContent="Home" /> <SidebarMoreMenu onChange={setMoreMenuValue} tooltipContent="Additional options" triggerTitle="Options" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }
With Collapsed Sidebar
When the sidebar is collapsed, the tooltipContent prop displays a tooltip on hover to identify the menu trigger.
function CollapsedSidebarExample() { const [activeIndex, setActiveIndex] = useState(0); const [moreMenuValue, setMoreMenuValue] = useState(); const [collapsed, setCollapsed] = useState(true); const mainItems = [ { title: 'Home', icon: 'home' }, { title: 'Assets', icon: 'chartPie' }, ]; const moreItems = [ { title: 'Rewards', icon: 'giftBox' }, { title: 'Settings', icon: 'cog' }, ]; const handleMoreMenuChange = (newValue) => { const moreIndex = moreItems.findIndex((item) => item.title === newValue) + mainItems.length; setActiveIndex(moreIndex); setMoreMenuValue(newValue); }; const handleItemClick = (index) => { setActiveIndex(index); setMoreMenuValue(undefined); }; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden"> <Sidebar collapsed={collapsed} logo={<LogoMark />} renderEnd={() => ( <IconButton accessibilityLabel={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} name={collapsed ? 'caretRight' : 'caretLeft'} onClick={() => setCollapsed(!collapsed)} /> )} > {mainItems.map((item, index) => ( <SidebarItem key={item.title} active={index === activeIndex} icon={item.icon} onClick={() => handleItemClick(index)} title={item.title} tooltipContent={item.title} /> ))} <SidebarMoreMenu active={activeIndex >= mainItems.length} onChange={handleMoreMenuChange} tooltipContent="More options" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }
Condensed Variant
SidebarMoreMenu adapts automatically to the sidebar's condensed variant.
function CondensedVariantExample() { const [activeIndex, setActiveIndex] = useState(0); const [moreMenuValue, setMoreMenuValue] = useState(); const mainItems = [ { title: 'Spot', icon: 'chartCandles' }, { title: 'Futures', icon: 'chartBar' }, ]; const moreItems = [ { title: 'Portfolio', icon: 'chartPie' }, { title: 'Orders', icon: 'documentation' }, { title: 'History', icon: 'orderHistory' }, ]; const handleMoreMenuChange = (newValue) => { const moreIndex = moreItems.findIndex((item) => item.title === newValue) + mainItems.length; setActiveIndex(moreIndex); setMoreMenuValue(newValue); }; const handleItemClick = (index) => { setActiveIndex(index); setMoreMenuValue(undefined); }; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden"> <Sidebar logo={<LogoMark foreground />} variant="condensed"> {mainItems.map((item, index) => ( <SidebarItem key={item.title} active={index === activeIndex} icon={item.icon} onClick={() => handleItemClick(index)} title={item.title} tooltipContent={item.title} /> ))} <SidebarMoreMenu active={activeIndex >= mainItems.length} onChange={handleMoreMenuChange} tooltipContent="More" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }
Styling
Border Radius
Use the borderRadius prop to customize the trigger's corner radius.
function BorderRadiusExample() { const [moreMenuValue, setMoreMenuValue] = useState(); const moreItems = [ { title: 'Settings', icon: 'cog' }, { title: 'Help', icon: 'questionCircle' }, ]; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden" gap={4}> <Sidebar logo={<LogoMark />}> <SidebarItem icon="home" title="Home" tooltipContent="Home" /> <SidebarMoreMenu borderRadius={100} onChange={setMoreMenuValue} tooltipContent="More" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> <Sidebar logo={<LogoMark />}> <SidebarItem icon="home" title="Home" tooltipContent="Home" /> <SidebarMoreMenu borderRadius={1000} onChange={setMoreMenuValue} tooltipContent="More" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }
Accessibility
SidebarMoreMenu automatically handles ARIA attributes for the dropdown menu pattern. Set tooltipContent to provide context when the sidebar is collapsed, ensuring users can identify the trigger via tooltip.
function AccessibilityExample() { const [moreMenuValue, setMoreMenuValue] = useState(); const moreItems = [ { title: 'Account Settings', icon: 'cog' }, { title: 'Help Center', icon: 'questionCircle' }, { title: 'Log Out', icon: 'logout' }, ]; return ( <HStack alignItems="flex-start" justifyContent="center" overflow="hidden"> <Sidebar collapsed logo={<LogoMark />}> <SidebarItem icon="home" title="Home" tooltipContent="Navigate to Home" /> <SidebarMoreMenu onChange={setMoreMenuValue} tooltipContent="Open additional navigation options" triggerTitle="More navigation options" value={moreMenuValue} > {moreItems.map((item) => ( <SelectOption key={item.title} description={item.title} media={<Icon name={item.icon} />} value={item.title} /> ))} </SidebarMoreMenu> </Sidebar> </HStack> ); }