DropdownMenu
TIP
If you need to customize your work of the dropdown menu, refer to the documentation for intergalactic/popper
The component is a wrapper over the intergalactic/dropdown that allows for the following:
- Displaying a list of options in a dropdown
- Scrolling through the list of options using keyboard
Basic usage
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
const Demo = () => {
return (
<DropdownMenu>
<DropdownMenu.Trigger tag={Button}>Actions</DropdownMenu.Trigger>
<DropdownMenu.Menu>
<DropdownMenu.Item>Save</DropdownMenu.Item>
<DropdownMenu.Item>Rename</DropdownMenu.Item>
<DropdownMenu.Item>Download</DropdownMenu.Item>
<DropdownMenu.Item>Delete</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
);
};
export default Demo;
Dropdown menu
There are a few ways to display the dropdown menu in this component.
First method
Use a combination of two components:
DropdownMenu.Popper
—for the dropdown layoutDropdownMenu.List
andScrollArea
—for the option list styles
This method works well when you need flexible customization of the dropdown menu content.
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
import Link from 'intergalactic/link';
import { Text } from 'intergalactic/typography';
import Notice from 'intergalactic/notice';
import SpinContainer from 'intergalactic/spin-container';
import FileExportM from 'intergalactic/icon/FileExport/m';
const Demo = () => {
const [loading, setLoading] = React.useState(false);
const handleClick = () => {
setLoading(true);
setTimeout(() => setLoading(false), 1000);
};
return (
<DropdownMenu>
<DropdownMenu.Trigger tag={Button}>
<Button.Addon>
<FileExportM />
</Button.Addon>
<Button.Text>Export</Button.Text>
</DropdownMenu.Trigger>
<DropdownMenu.Popper wMax='256px'>
<SpinContainer loading={loading}>
<DropdownMenu.List>
<DropdownMenu.Item onClick={handleClick}>Excel</DropdownMenu.Item>
<DropdownMenu.Item onClick={handleClick}>CSV</DropdownMenu.Item>
<DropdownMenu.Item onClick={handleClick}>CSV Semicolon</DropdownMenu.Item>
</DropdownMenu.List>
<Notice
theme='warning'
style={{
padding: 'var(--intergalactic-spacing-3x) var(--intergalactic-spacing-2x)',
borderWidth: 0,
borderTopWidth: '1px',
borderRadius:
'0 0 var(--intergalactic-rounded-medium) var(--intergalactic-rounded-medium)',
}}
>
<Notice.Content>
<Text tag='strong' mb={1} style={{ display: 'block' }}>
Export failed
</Text>
<Text>
If the problem persists, please contact us at{' '}
<Link inline href='mailto:feedback@semrush.com'>
feedback@semrush.com
</Link>
</Text>
</Notice.Content>
</Notice>
</SpinContainer>
</DropdownMenu.Popper>
</DropdownMenu>
);
};
export default Demo;
Second method
The easiest way is to use DropdownMenu.Menu
.
This is best when you only need to manage the content within the options list.
DropdownMenu.Menu
is a wrapper around DropdownMenu.Popper
and DropdownMenu.List
, and all props pass through to DropdownMenu.List
.
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import { ButtonTrigger } from 'intergalactic/base-trigger';
import { Text } from 'intergalactic/typography';
import { Flex } from 'intergalactic/flex-box';
const Demo = () => {
return (
<Flex direction='column'>
<Text tag='label' size={200} htmlFor='dropdown-menu-children-items'>
Your choice
</Text>
<DropdownMenu>
<DropdownMenu.Trigger
tag={ButtonTrigger}
mt={2}
mr='auto'
id='dropdown-menu-children-items'
>
Choose an item
</DropdownMenu.Trigger>
{/* Adding max-height to the dropdown menu */}
<DropdownMenu.Menu hMax={'180px'}>
<DropdownMenu.Group title={'List heading'} subTitle={'Subtitle'}>
<DropdownMenu.Item>Item 1</DropdownMenu.Item>
<DropdownMenu.Item>Item 2</DropdownMenu.Item>
<DropdownMenu.Item>Item 3</DropdownMenu.Item>
<DropdownMenu.Item>Item 4</DropdownMenu.Item>
<DropdownMenu.Item>Item 5</DropdownMenu.Item>
<DropdownMenu.Item>Item 6</DropdownMenu.Item>
<DropdownMenu.Item>Item 7</DropdownMenu.Item>
<DropdownMenu.Item>Item 8</DropdownMenu.Item>
<DropdownMenu.Item>Item 9</DropdownMenu.Item>
</DropdownMenu.Group>
</DropdownMenu.Menu>
</DropdownMenu>
</Flex>
);
};
export default Demo;
Menu item types
The component offers several options for laying out list item types:
DropdownMenu.Item
: A list element that can be selected with the keyboard.DropdownMenu.Item.Content
: The content within an item, used when you need to include a hint or submenu.DropdownMenu.Item.Hint
: A subheading or message with additional information (can't be selected with the keyboard).
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
import Tooltip from 'intergalactic/tooltip';
const TooltipContent = () => {
const tooltipIndex = React.useContext(DropdownMenu.selectedIndexContext);
return <div>Some tooltip for {tooltipIndex + 1}</div>;
};
const Demo = () => {
return (
<DropdownMenu>
<DropdownMenu.Trigger tag={Button}>Check the options</DropdownMenu.Trigger>
<DropdownMenu.Menu>
<Tooltip placement={'right'} timeout={[0, 50]}>
<DropdownMenu.Group title={'Title'} subTitle={'Subtitle'}>
<DropdownMenu.Item tag={Tooltip.Trigger}>
<DropdownMenu.Item.Content>Item 1</DropdownMenu.Item.Content>
</DropdownMenu.Item>
<DropdownMenu.Item tag={Tooltip.Trigger}>
<DropdownMenu.Item.Content>Item 2</DropdownMenu.Item.Content>
<DropdownMenu.Item.Hint>Hint for item 2</DropdownMenu.Item.Hint>
</DropdownMenu.Item>
<DropdownMenu.Item tag={Tooltip.Trigger}>
<DropdownMenu.Item.Content>Item 3</DropdownMenu.Item.Content>
<DropdownMenu.Item.Hint>Hint for item 3</DropdownMenu.Item.Hint>
</DropdownMenu.Item>
<DropdownMenu.Item tag={Tooltip.Trigger}>
<DropdownMenu.Item.Content>Item 4</DropdownMenu.Item.Content>
</DropdownMenu.Item>
</DropdownMenu.Group>
<Tooltip.Popper w={120} aria-hidden={true}>
<TooltipContent />
</Tooltip.Popper>
</Tooltip>
</DropdownMenu.Menu>
</DropdownMenu>
);
};
export default Demo;
Menu item with actions
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import { Flex } from 'intergalactic/flex-box';
import TrashM from 'intergalactic/icon/Trash/m';
import PlusM from 'intergalactic/icon/MathPlus/m';
import Button from 'intergalactic/button';
import ChevronRightIcon from '@semcore/icon/ChevronRight/m';
const Demo = () => {
return (
<DropdownMenu>
<DropdownMenu.Trigger tag={Button}>List item with actions</DropdownMenu.Trigger>
<DropdownMenu.Menu>
<DropdownMenu.Item>Item 1</DropdownMenu.Item>
<DropdownMenu.Item>Item 2</DropdownMenu.Item>
<DropdownMenu.Item>
<DropdownMenu inlineActions placement={'right'}>
<Flex justifyContent='space-between'>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 3
</DropdownMenu.Item.Content>
<DropdownMenu.Actions gap={1}>
<DropdownMenu.Item tag={Button} addonLeft={PlusM} aria-label={'Add new'} />
<DropdownMenu.Item tag={Button} addonLeft={TrashM} aria-label={'Delete'} />
</DropdownMenu.Actions>
</Flex>
</DropdownMenu>
</DropdownMenu.Item>
<DropdownMenu.Item>
<DropdownMenu placement={'right'} interaction={'hover'} timeout={[0, 300]}>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 4
<ChevronRightIcon color='icon-secondary-neutral' />
</DropdownMenu.Item.Content>
<DropdownMenu.Menu>
<DropdownMenu.Item>Add</DropdownMenu.Item>
<DropdownMenu.Item>Delete</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
);
};
export default Demo;
Render-function
Like with lower-level components, you can access the component's logic by passing a render function into the body.
You can find the list of available methods in the Context section of the API.
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
import { Box } from '@semcore/flex-box';
const Demo = () => {
return (
<DropdownMenu>
{(props, handlers) => {
const {
getTriggerProps, // encapsulates Trigger logic
getPopperProps, // encapsulates Popper logic
getListProps, // encapsulates List logic
getItemProps, // // encapsulates Item logic
} = props;
const popperProps = getPopperProps();
return (
<React.Fragment>
<Button {...getTriggerProps()}>Dropdown menu with render function</Button>
<Box
{...popperProps}
hidden={!popperProps.visible}
zIndex={10}
p={2}
style={{
backgroundColor: 'var(--intergalactic-bg-primary-neutral, #FFF)',
border: '1px solid gray',
}}
>
<ul {...getListProps()}>
<li {...getItemProps()}>Option 1</li>
<li {...getItemProps()}>Option 2</li>
<li {...getItemProps()}>Option 3</li>
<li {...getItemProps()}>Option 4</li>
<li {...getItemProps()}>Option 5</li>
</ul>
<button type='button' onClick={() => handlers.visible(false)}>
Close me
</button>
<button type='button' onClick={() => handlers.highlightedIndex(2)}>
Highlight item 3
</button>
</Box>
</React.Fragment>
);
}}
</DropdownMenu>
);
};
export default Demo;
Nested menus
import React from 'react';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
import ChevronRightIcon from 'intergalactic/icon/ChevronRight/m';
const Demo = () => {
return (
<DropdownMenu>
<DropdownMenu.Trigger tag={Button}>Nested menus</DropdownMenu.Trigger>
<DropdownMenu.Menu>
<DropdownMenu.Item>Item 1</DropdownMenu.Item>
<DropdownMenu.Item>Item 2</DropdownMenu.Item>
<DropdownMenu.Item>Item 3</DropdownMenu.Item>
<DropdownMenu.Item>
<DropdownMenu placement='right' interaction='hover' timeout={[0, 300]}>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 4
<DropdownMenu.Item.Addon tag={ChevronRightIcon} color='icon-secondary-neutral' />
</DropdownMenu.Item.Content>
<DropdownMenu.Menu w={120}>
<DropdownMenu.Item>
<DropdownMenu placement='right' interaction='hover' timeout={[0, 300]}>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 4.1
<DropdownMenu.Item.Addon
tag={ChevronRightIcon}
color='icon-secondary-neutral'
/>
</DropdownMenu.Item.Content>
<DropdownMenu.Menu w={120}>
<DropdownMenu.Item>Item 4.1.1</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.1.2</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.1.3</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DropdownMenu.Item>
<DropdownMenu.Item>
<DropdownMenu placement='right' interaction='hover' timeout={[0, 300]}>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 4.2
<DropdownMenu.Item.Addon
tag={ChevronRightIcon}
color='icon-secondary-neutral'
/>
</DropdownMenu.Item.Content>
<DropdownMenu.Menu w={120}>
<DropdownMenu.Item>
<DropdownMenu placement='right' interaction='hover' timeout={[0, 300]}>
<DropdownMenu.Item.Content tag={DropdownMenu.Trigger}>
Item 4.2.1
<DropdownMenu.Item.Addon
tag={ChevronRightIcon}
color='icon-secondary-neutral'
/>
</DropdownMenu.Item.Content>
<DropdownMenu.Menu w={120}>
<DropdownMenu.Item>Item 4.2.1.1</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.2.1.2</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.2.1.3</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.2.2</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.2.3</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DropdownMenu.Item>
<DropdownMenu.Item>Item 4.3</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DropdownMenu.Item>
<DropdownMenu.Item>Item 5</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
);
};
export default Demo;
Last updated: