--- meta: title: Dropdown description: 'Dropdowns expose additional content that "drops down" in a panel.' layout: component --- Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it. Dropdowns are designed to work well with [menus](/components/menu) to provide a list of options the user can select from. However, dropdowns can also be used in lower-level applications (e.g. [color picker](/components/color-picker)). The API gives you complete control over showing, hiding, and positioning the panel. ```html:preview Dropdown Dropdown Item 1 Dropdown Item 2 Dropdown Item 3 Checkbox Disabled Prefix Suffix Icon ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlIcon from '@shoelace-style/shoelace/dist/react/icon'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => ( Dropdown Dropdown Item 1 Dropdown Item 2 Dropdown Item 3 Checkbox Disabled Prefix Suffix Icon ); ``` ## Examples ### Getting the Selected Item When dropdowns are used with [menus](/components/menu), you can listen for the [`sl-select`](/components/menu#events) event to determine which menu item was selected. The menu item element will be exposed in `event.detail.item`. You can set `value` props to make it easier to identify commands. ```html:preview ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => { function handleSelect(event) { const selectedItem = event.detail.item; console.log(selectedItem.value); } return ( Edit Cut Copy Paste ); }; ``` Alternatively, you can listen for the `click` event on individual menu items. Note that, using this approach, disabled menu items will still emit a `click` event. ```html:preview ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => { function handleCut() { console.log('cut'); } function handleCopy() { console.log('copy'); } function handlePaste() { console.log('paste'); } return ( Edit Cut Copy Paste ); }; ``` ### Placement The preferred placement of the dropdown can be set with the `placement` attribute. Note that the actual position may vary to ensure the panel remains in the viewport. ```html:preview Edit Cut Copy Paste Find Replace ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => ( Edit Cut Copy Paste Find Replace ); ``` ### Distance The distance from the panel to the trigger can be customized using the `distance` attribute. This value is specified in pixels. ```html:preview Edit Cut Copy Paste Find Replace ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => ( Edit Cut Copy Paste Find Replace ); ``` ### Skidding The offset of the panel along the trigger can be customized using the `skidding` attribute. This value is specified in pixels. ```html:preview Edit Cut Copy Paste Find Replace ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const App = () => ( Edit Cut Copy Paste Find Replace ); ``` ### Submenus To create a submenu, nest an `` element in a [menu item](/components/menu-item). ```html:preview Edit Undo Redo Cut Copy Paste Find Find… Find Next Find Previous Transformations Make uppercase Make lowercase Capitalize ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const css = ` .dropdown-hoist { border: solid 2px var(--sl-panel-border-color); padding: var(--sl-spacing-medium); overflow: hidden; } `; const App = () => ( <> Edit Undo Redo Cut Copy Paste Find Find… Find Next Find Previous Transformations Make uppercase Make lowercase Capitalize ); ``` :::warning As a UX best practice, avoid using more than one level of submenu when possible. ::: ### Hoisting Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details. ```html:preview ``` ```jsx:react import SlButton from '@shoelace-style/shoelace/dist/react/button'; import SlDivider from '@shoelace-style/shoelace/dist/react/divider'; import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown'; import SlMenu from '@shoelace-style/shoelace/dist/react/menu'; import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; const css = ` .dropdown-hoist { border: solid 2px var(--sl-panel-border-color); padding: var(--sl-spacing-medium); overflow: hidden; } `; const App = () => ( <>
No Hoist Item 1 Item 2 Item 3 Hoist Item 1 Item 2 Item 3
); ```