Dropdown displays a list of actions, options or links. It is triggered when a user interacts with a Button, Textfield or other control. Dropdown allows for complex functionality that can’t be accomplished with SelectList.
also known as Menu, Contextual Menu
Props
Usage guidelines
- Displaying a list of actions, options, or links. Usually displays 3 or more options.
- Allowing complex functionality that a SelectList can't accomplish.
- Taking immediate action or navigating users to another view.
- In cases when there are less than 3 items in the list, and there is space to display all options. Consider RadioGroup or Checkboxes instead.
- When it is desirable to filter a long list of options. Use ComboBox instead.
- Displaying a list of actions or options using the browser's native select functionality. Use SelectList instead.
Best practices
Use Dropdown when features such as subtext, custom headers or badges are needed, since this functionality is not available in SelectList.
Use Dropdown for a simple list of items. Use SelectList instead for the added native mobile functionality. The exception to this is multiple Dropdowns or SelectLists that could be grouped together to create visual inconsistency, such as filters. In this case, use Dropdowns for all.
Order the items in Dropdown either alphabetically or by usage. Place destructive actions at the bottom.
Attach Tooltips to menu items. Use the `subtext` property if additional explanation is needed.
Add an icon indicator when links are external using the isExternal
prop. External links are either links outside of Pinterest or another sub-site of Pinterest.
Add custom elements within Dropdown. While some custom elements may be technically possible, it is best to avoid customization that becomes difficult to maintain.
Accessibility
ARIA attributes
Remember to include the following ARIA attributes on the element used for the anchor
prop:
accessibilityControls
: lets the screen reader know that this element controls the Dropdown menu (should match theid
property passed to Dropdown). Populates the aria-controls attribute.accessibilityHaspopup
: lets the screen reader know that there is a Dropdown menu linked to the trigger. Populates the aria-haspopup attribute.accessibilityExpanded
: informs the screen reader whether the Dropdown menu is currently open or closed. Populates the aria-expanded attribute.
Keyboard interaction
- Hitting
Enter
orSpace
key on the Dropdown's trigger opens the menu Escape
key closes the menu, while moving focus back on the Dropdown's trigger- Arrow keys are used to navigate items within the menu
Enter
key selects an item within the MenuTab
orShift + Tab
close the menu and move focus accordingly
Custom item content limitations
If using custom content, do not include interactive elements, like a TextArea or Button. Because Dropdown.Item and Dropdown.Link already act as buttons and links respectively, they cannot include focusable elements as children. Learn more about nested interactive controls
import { Fragment, useRef, useState } from 'react'; import { Avatar, Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, Text, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="custom-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="add" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="custom-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Section label="Currently in"> <Dropdown.Link href="#" option={{ value: 'item 1', label: 'Custom link 1' }} onClick={({ event }) => event.preventDefault()} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Tia" size="md" src="https://i.ibb.co/7tGKGvb/shanice.jpg" /> <Flex direction="column"> <Text>Tia Marz</Text> <Text size="200" color="subtle"> Personal </Text> <Text size="200" color="subtle"> travel@theworld.com </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="Your accounts"> <Dropdown.Link href="#" option={{ value: 'item 2', label: 'Another custom link' }} onClick={({ event }) => event.preventDefault()} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Bruno" size="md" src="https://i.ibb.co/4Mbhbnb/Bruno.jpg" /> <Flex direction="column"> <Text>Bruno</Text> <Text size="200" color="subtle"> Business </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="More options"> <Dropdown.Link href="#" option={{ value: 'settings', label: 'Settings' }} onClick={({ event }) => event.preventDefault()} /> <Dropdown.Link href="#" isExternal option={{ value: 'help', label: 'Get help' }} onClick={({ event }) => event.preventDefault()} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Localization
Truncation
When the text of the Dropdown.Item becomes longer than the width of the menu, either intentionally or through localization, the text will truncate at one line. Subtext will wrap as needed to display the full text.
import { Fragment, useRef, useState } from 'react'; import { Box, Button, CompositeZIndex, Dropdown, FixedZIndex, Flex, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <Button accessibilityControls="truncation-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup iconEnd="arrow-down" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" text="Menu" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="truncation-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Homefeed anpassen', label: 'Homefeed anpassen', subtext: 'Aktualisieren Sie Ihren Homefeed, um Ihre Vorlieben und Ideen besser widerzuspiegeln', }} selected={selected} /> <Dropdown.Link href="https://help.pinterest.com/en?source=gear_menu_web" isExternal option={{ value: 'Hilfe anfordern', label: 'Hilfe anfordern' }} onClick={({ event }) => event.preventDefault()} /> <Dropdown.Link href="https://policy.pinterest.com/en/privacy-policy" isExternal option={{ value: 'Nutzungsbedingungen und Datenschutzrichtlinien anzeigen', label: 'Nutzungsbedingungen und Datenschutzrichtlinien anzeigen', }} onClick={({ event }) => event.preventDefault()} /> </Dropdown> )} </Fragment> ); }
Subcomponents
Dropdown.Item
Use Dropdown.Item for action & selection, when the Dropdown item triggers an action or selects an option.
Dropdown.Item Props
Dropdown.Link
Use Dropdown.Link for navigation, when the Dropdown item navigates to a new page.
Dropdown.Link Props
Dropdown.Section
Use Dropdown.Section to create hierarchy within a single Dropdown.
Dropdown.Section Props
Variants
Types of items
import { Fragment, useRef, useState } from 'react'; import { Box, Button, CompositeZIndex, Dropdown, FixedZIndex, Flex, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <Button accessibilityControls="action-variant-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup iconEnd="arrow-down" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" text={selected ? selected.label : 'Display'} /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="action-variant-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Item onSelect={onSelect} option={{ value: 'Cozy', label: 'Cozy' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Comfy', label: 'Comfy' }} selected={selected} /> </Dropdown> )} </Fragment> ); }
Typically a Dropdown item triggers an action, like “Hide a Pin”, or makes a selection, like “Cozy” for a layout setting. Use Dropdown.Item for these use cases. onSelect
handles the user interaction, with the optional selected
indicating the currently-selected item.
import { Fragment, useRef, useState } from 'react'; import { Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="link-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="arrow-down" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="link-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Link href="https://pinterest.com" option={{ value: 'Create new board', label: 'Create new board' }} onClick={({ event }) => event.preventDefault()} /> <Dropdown.Link href="https://help.pinterest.com/en?source=gear_menu_web" isExternal onClick={({ event }) => event.preventDefault()} option={{ value: 'Get help', label: 'Get help' }} /> <Dropdown.Link href="https://policy.pinterest.com/en/privacy-policy" isExternal option={{ value: 'See terms and privacy', label: 'See terms and privacy', }} onClick={({ event }) => event.preventDefault()} /> </Dropdown> )} </Fragment> ); }
If an item navigates to a new page, use Dropdown.Link with the required href
prop. If the item navigates to a page outside of the current context, (either a non-Pinterest site or a different Pinterest sub-site), the isExternal
prop should also be specified to display the "up-right" icon. Optional additional actions to be taken on navigation are handled by onClick
. Dropdown.Link can be paired with GlobalEventsHandlerProvider. See GlobalEventsHandlerProvider to learn more about link navigation.
Sections
Dropdown can also be composed of Dropdown.Section(s), which simply require a label. Use Dropdown.Section(s) to create hierarchy within a single Dropdown. Dropdown.Sections, Dropdown.Items and Dropdown.Links can be mixed as needed.
import { Fragment, useRef, useState } from 'react'; import { Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="sections-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" bgColor="lightGray" icon="add" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="sections-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Section label="Create"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pin', label: 'Pin' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Story Pin', label: 'Story Pin' }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="Add"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Note', label: 'Note' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Section', label: 'Section' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Custom header
Dropdown can also contain a custom header by specifying headerContent
, which always appears at the very top of the menu. It can be used instead of a section header if the menu contains only one type of content that needs additional description. It can contain anything, but most often will contain just text and/or a link.
import { Fragment, useRef, useState } from 'react'; import { Box, Button, CompositeZIndex, Dropdown, FixedZIndex, Flex, Link, Text, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [selected, setSelected] = useState(null); const [open, setOpen] = useState(false); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <Button accessibilityControls="header-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup iconEnd="arrow-down" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" text="Menu" /> </Box> </Flex> {open && ( <Dropdown zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} anchor={anchorRef.current} headerContent={ <Text align="start" size="100"> This Pin was inspired by your{' '} <Text weight="bold" size="100"> <Link href="https://pinterest.com">recent activity</Link> </Text> </Text> } id="header-dropdown-example" onDismiss={() => { setOpen(false); }} > <Dropdown.Item onSelect={() => alert('Pin has been hidden')} option={{ value: 'item 1', label: 'Hide Pin' }} selected={selected} /> <Dropdown.Link href="#" isExternal onClick={({ event }) => event.preventDefault()} option={{ value: 'item 2', label: 'Report Pin', }} /> <Dropdown.Section label="View options"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'item 4', label: 'Compact' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'item 5', label: 'List' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Subtext
Each Dropdown item can also contain subtext
below the label. This subtext
will wrap if needed. Use this text to add an additional description of the Dropdown item.
import { Fragment, useRef, useState } from 'react'; import { Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="subtext-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="arrow-down" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="subtext-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Section label="Accounts"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pepper the Pupper', label: 'Pepper the Pupper', subtext: 'pepper@thepupper.com', }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Mizu the Kitty', label: 'Mizu the Kitty', subtext: 'mizu@thekitty.com', }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="More options"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Tune your home feed', label: 'Tune your home feed', }} selected={selected} /> <Dropdown.Link href="https://pinterest.com" isExternal option={{ value: 'Get help', label: 'Get help' }} onClick={({ event }) => event.preventDefault()} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Badges
A Badge can be used to indicate a new product surface or feature within the Dropdown using badgeText
. Multiple badges within a Dropdown should be avoided when possible.
import { Fragment, useRef, useState } from 'react'; import { Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); const anchorRef = useRef(null); const onSelect = ({ item }) => setSelected(item); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="badges-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="add" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="badges-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Section label="Create"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pin', label: 'Pin' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Story Pin', label: 'Story Pin' }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="Add"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Note', label: 'Note' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Section', label: 'Section' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Custom item content
If needed, users can supply custom content to each Dropdown.Item or Dropdown.Link. This can be useful when extra functionality is needed, like showing an Avatar. However, please use with caution and only when absolutely necessary.
To ensure the entire width of the item is clickable, you will likely need to surround your custom content with a full-width Box.
import { Fragment, useRef, useState } from 'react'; import { Avatar, Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, Text, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box margin={2}> <IconButton accessibilityControls="custom-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="add" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="custom-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > <Dropdown.Section label="Currently in"> <Dropdown.Link href="#" option={{ value: 'item 1', label: 'Custom link 1' }} onClick={({ event }) => event.preventDefault()} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Tia" size="md" src="https://i.ibb.co/7tGKGvb/shanice.jpg" /> <Flex direction="column"> <Text>Tia Marz</Text> <Text size="200" color="subtle"> Personal </Text> <Text size="200" color="subtle"> travel@theworld.com </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="Your accounts"> <Dropdown.Link href="#" option={{ value: 'item 2', label: 'Another custom link' }} onClick={({ event }) => event.preventDefault()} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Bruno" size="md" src="https://i.ibb.co/4Mbhbnb/Bruno.jpg" /> <Flex direction="column"> <Text>Bruno</Text> <Text size="200" color="subtle"> Business </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="More options"> <Dropdown.Link href="#" option={{ value: 'settings', label: 'Settings' }} onClick={({ event }) => event.preventDefault()} /> <Dropdown.Link href="#" isExternal option={{ value: 'help', label: 'Get help' }} onClick={({ event }) => event.preventDefault()} /> </Dropdown.Section> </Dropdown> )} </Fragment> ); }
Subcomponent composability
Under the hood, Dropdown executes two actions: recognizing subcomponents by display name and sequencially indexing each subcomponent for keyboard navigation.
Dropdown requires its own subcomponents as children to build the list of actions.
When building a Dropdown, we might want to render different combinations of subcomponents conditionally. Dropdown supports simple conditional rendering of subcomponents lists wrapped in React.Fragment as well as consecutive arrays of subcomponent arrays. See the example below which illustrates both of these cases. More logic complexity might break the correct Dropdown behavior.
import { Fragment, useRef, useState } from 'react'; import { Box, CompositeZIndex, Dropdown, FixedZIndex, Flex, IconButton, Label, Switch, Text, } from 'gestalt'; export default function CustomIconButtonPopoverExample() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [switched, setSwitched] = useState(true); const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <Fragment> <Flex justifyContent="center" width="100%" height="100%"> <Box> <Box margin={2}> <Box paddingX={2}> <Label htmlFor="dropdown-example"> <Text>Toggle Dropdown subcomponents</Text> </Label> </Box> <Switch onChange={() => setSwitched((value) => !value)} id="dropdown-example" switched={switched} /> </Box> <IconButton accessibilityControls="custom-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup accessibilityLabel="More Options" icon="add" iconColor="darkGray" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" /> </Box> </Flex> {open && ( <Dropdown anchor={anchorRef.current} id="custom-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} > {switched ? ( <Fragment> <Dropdown.Link isExternal href="#" onClick={({ event }) => event.preventDefault()} option={{ value: 'item 1', label: 'Custom link 1' }} /> <Dropdown.Link isExternal href="#" onClick={({ event }) => event.preventDefault()} option={{ value: 'item 2', label: 'Another custom link' }} /> </Fragment> ) : ( <Fragment> {[1, 2, 3, 4, 5, 6].map((x) => ( <Dropdown.Item key={x} onSelect={() => {}} option={{ value: x.toString(), label: x.toString() }} /> ))} {[7, 8, 9, 10, 11, 12].map((x) => ( <Dropdown.Item key={x} onSelect={() => {}} option={{ value: x.toString(), label: x.toString() }} /> ))} </Fragment> )} </Dropdown> )} </Fragment> ); }
Mobile
Dropdown requires DeviceTypeProvider to enable its mobile user interface. The example below shows the mobile platform UI and its implementation.
SheetMobile has animation. To learn more about Dropdown.Link´s mobileOnDismissStart
, see the animation variant in SheetMobile. mobileOnDismissStart
is the equivalent of onDismissStart
in SheetMobile.
import { useRef, useState } from 'react'; import { Avatar, Box, Button, CompositeZIndex, DeviceTypeProvider, Dropdown, FixedZIndex, Flex, Link, Text, } from 'gestalt'; export default function Example() { const PAGE_HEADER_ZINDEX = new FixedZIndex(10); const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <DeviceTypeProvider deviceType="mobile"> <Box display="flex" justifyContent="center" width="100%" margin={2}> <Button accessibilityControls="demo-dropdown-example" accessibilityExpanded={open} accessibilityHaspopup iconEnd="arrow-down" onClick={() => setOpen((prevVal) => !prevVal)} ref={anchorRef} selected={open} size="lg" text="Menu" /> </Box> {open && ( <Dropdown anchor={anchorRef.current} id="demo-dropdown-example" onDismiss={() => setOpen(false)} zIndex={new CompositeZIndex([PAGE_HEADER_ZINDEX])} disableMobileUI={false} headerContent={ <Text align="start" size="100" inline> This Pin was inspired by your{' '} <Link display="inline" href="https://pinterest.com"> recent activity </Link> </Text> } > <Dropdown.Section label="Currently in"> <Dropdown.Link href="#" onClick={({ event }) => event.preventDefault()} option={{ value: 'item 1', label: 'Custom link 1' }} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Tia" size="md" src="https://i.ibb.co/7tGKGvb/shanice.jpg" /> <Flex direction="column"> <Text>Tia Marz</Text> <Text size="200" color="subtle"> Personal </Text> <Text size="200" color="subtle"> travel@theworld.com </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="Your accounts"> <Dropdown.Link onClick={({ event }) => event.preventDefault()} href="#" option={{ value: 'item 2', label: 'Another custom link' }} > <Box width="100%"> <Flex gap={2} alignItems="center"> <Avatar name="Bruno" size="md" src="https://i.ibb.co/4Mbhbnb/Bruno.jpg" /> <Flex direction="column"> <Text>Bruno</Text> <Text size="200" color="subtle"> Business </Text> </Flex> </Flex> </Box> </Dropdown.Link> </Dropdown.Section> <Dropdown.Section label="More options"> <Dropdown.Link onClick={({ event }) => event.preventDefault()} href="#" option={{ value: 'settings', label: 'Settings' }} /> <Dropdown.Link onClick={({ event, mobileOnDismissStart }) => { event.preventDefault(); mobileOnDismissStart(); }} href="#" isExternal option={{ value: 'help', label: 'Get help' }} /> </Dropdown.Section> </Dropdown> )} </DeviceTypeProvider> ); }
Component quality checklist
Quality item | Status | Status description |
---|---|---|
Figma Library | Ready | Component is available in Figma for web and mobile web. |
Responsive Web | Ready | Component responds to changing viewport sizes in web and mobile web. |
Related
Button, IconButton
It is most common to anchor Dropdown to Button or IconButton.
ScrollBoundaryContainer
ScrollableContainer is needed for proper positioning when the Dropdown is located within a scrolling container. The use of ScrollableContainer ensures the Dropdown remains attached to its anchor when scrolling.
SelectList
If users need to select from a short, simple list (without needing sections, subtext details, or the ability to filter the list), use SelectList.
ComboBox
If users need the ability to choose an option by typing in an input and filtering a long list of options, use ComboBox.
GlobalEventsHandlerProvider
GlobalEventsHandlerProvider allows external link navigation control across all children components with link behavior.