Skip to main content
Since Shoelace 2.0 Code stable Pattern stable Figma ready

Dropdown

sl-dropdown

Dropdowns expose additional content that “drops down” in a panel.

Examples

Basic Dropdown

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 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). The API gives you complete control over showing, hiding, and positioning the panel.

Dropdown Dropdown Item 1 Dropdown Item 2 Dropdown Item 3 Checkbox Disabled Prefix Suffix Icon
<sl-dropdown>
  <sl-button slot="trigger" caret>Dropdown</sl-button>
  <sl-menu>
    <sl-menu-item>Dropdown Item 1</sl-menu-item>
    <sl-menu-item>Dropdown Item 2</sl-menu-item>
    <sl-menu-item>Dropdown Item 3</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item type="checkbox" checked>Checkbox</sl-menu-item>
    <sl-menu-item disabled>Disabled</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item>
      Prefix
      <sl-icon slot="prefix" name="gift"></sl-icon>
    </sl-menu-item>
    <sl-menu-item>
      Suffix Icon
      <sl-icon slot="suffix" name="heart"></sl-icon>
    </sl-menu-item>
  </sl-menu>
</sl-dropdown>
sl-dropdown
  sl-button slot="trigger" caret=true Dropdown
  sl-menu
    sl-menu-item Dropdown Item 1
    sl-menu-item Dropdown Item 2
    sl-menu-item Dropdown Item 3
    sl-divider
    sl-menu-item type="checkbox" checked=true Checkbox
    sl-menu-item disabled=true Disabled
    sl-divider
    sl-menu-item
      | Prefix
      sl-icon slot="prefix" name="gift"
    sl-menu-item
      | Suffix Icon
      sl-icon slot="suffix" name="heart"

Getting the Selected Item

When dropdowns are used with menus, you can listen for the sl-select 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.

<div class="dropdown-selection">
  <sl-dropdown>
    <sl-button slot="trigger" caret>Edit</sl-button>
    <sl-menu>
      <sl-menu-item value="cut">Cut</sl-menu-item>
      <sl-menu-item value="copy">Copy</sl-menu-item>
      <sl-menu-item value="paste">Paste</sl-menu-item>
    </sl-menu>
  </sl-dropdown>
</div>

<script>
  const container = document.querySelector('.dropdown-selection');
  const dropdown = container.querySelector('sl-dropdown');

  dropdown.addEventListener('sl-select', event => {
    const selectedItem = event.detail.item;
    console.log(selectedItem.value);
  });
</script>
div.dropdown-selection
  sl-dropdown
    sl-button slot="trigger" caret=true Edit
    sl-menu
      sl-menu-item value="cut" Cut
      sl-menu-item value="copy" Copy
      sl-menu-item value="paste" Paste

javascript:
  const container = document.querySelector(.dropdown-selection);
  const dropdown = container.querySelector(sl-dropdown);

  dropdown.addEventListener(sl-select, event => {
    const selectedItem = event.detail.item;
    console.log(selectedItem.value);
  });

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.

<div class="dropdown-selection-alt">
  <sl-dropdown>
    <sl-button slot="trigger" caret>Edit</sl-button>
    <sl-menu>
      <sl-menu-item value="cut">Cut</sl-menu-item>
      <sl-menu-item value="copy">Copy</sl-menu-item>
      <sl-menu-item value="paste">Paste</sl-menu-item>
    </sl-menu>
  </sl-dropdown>
</div>

<script>
  const container = document.querySelector('.dropdown-selection-alt');
  const cut = container.querySelector('sl-menu-item[value="cut"]');
  const copy = container.querySelector('sl-menu-item[value="copy"]');
  const paste = container.querySelector('sl-menu-item[value="paste"]');

  cut.addEventListener('click', () => console.log('cut'));
  copy.addEventListener('click', () => console.log('copy'));
  paste.addEventListener('click', () => console.log('paste'));
</script>
div.dropdown-selection-alt
  sl-dropdown
    sl-button slot="trigger" caret=true Edit
    sl-menu
      sl-menu-item value="cut" Cut
      sl-menu-item value="copy" Copy
      sl-menu-item value="paste" Paste

javascript:
  const container = document.querySelector(.dropdown-selection-alt);
  const cut = container.querySelector(sl-menu-item[value=cut]);
  const copy = container.querySelector(sl-menu-item[value=copy]);
  const paste = container.querySelector(sl-menu-item[value=paste]);

  cut.addEventListener(click, () => console.log(cut));
  copy.addEventListener(click, () => console.log(copy));
  paste.addEventListener(click, () => console.log(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.

Edit Cut Copy Paste Find Replace
<sl-dropdown placement="top-start">
  <sl-button slot="trigger" caret>Edit</sl-button>
  <sl-menu>
    <sl-menu-item>Cut</sl-menu-item>
    <sl-menu-item>Copy</sl-menu-item>
    <sl-menu-item>Paste</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item>Find</sl-menu-item>
    <sl-menu-item>Replace</sl-menu-item>
  </sl-menu>
</sl-dropdown>
sl-dropdown placement="top-start"
  sl-button slot="trigger" caret=true Edit
  sl-menu
    sl-menu-item Cut
    sl-menu-item Copy
    sl-menu-item Paste
    sl-divider
    sl-menu-item Find
    sl-menu-item Replace

Distance

The distance from the panel to the trigger can be customized using the distance attribute. This value is specified in pixels.

Edit Cut Copy Paste Find Replace
<sl-dropdown distance="30">
  <sl-button slot="trigger" caret>Edit</sl-button>
  <sl-menu>
    <sl-menu-item>Cut</sl-menu-item>
    <sl-menu-item>Copy</sl-menu-item>
    <sl-menu-item>Paste</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item>Find</sl-menu-item>
    <sl-menu-item>Replace</sl-menu-item>
  </sl-menu>
</sl-dropdown>
sl-dropdown distance="30"
  sl-button slot="trigger" caret=true Edit
  sl-menu
    sl-menu-item Cut
    sl-menu-item Copy
    sl-menu-item Paste
    sl-divider
    sl-menu-item Find
    sl-menu-item Replace

Skidding

The offset of the panel along the trigger can be customized using the skidding attribute. This value is specified in pixels.

Edit Cut Copy Paste Find Replace
<sl-dropdown skidding="30">
  <sl-button slot="trigger" caret>Edit</sl-button>
  <sl-menu>
    <sl-menu-item>Cut</sl-menu-item>
    <sl-menu-item>Copy</sl-menu-item>
    <sl-menu-item>Paste</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item>Find</sl-menu-item>
    <sl-menu-item>Replace</sl-menu-item>
  </sl-menu>
</sl-dropdown>
sl-dropdown skidding="30"
  sl-button slot="trigger" caret=true Edit
  sl-menu
    sl-menu-item Cut
    sl-menu-item Copy
    sl-menu-item Paste
    sl-divider
    sl-menu-item Find
    sl-menu-item Replace

To create a submenu, nest an <sl-menu slot="submenu"> element in a menu item.

Edit Undo Redo Cut Copy Paste Find Find… Find Next Find Previous Transformations Make uppercase Make lowercase Capitalize
<sl-dropdown>
  <sl-button slot="trigger" caret>Edit</sl-button>

  <sl-menu style="max-width: 200px;">
    <sl-menu-item value="undo">Undo</sl-menu-item>
    <sl-menu-item value="redo">Redo</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item value="cut">Cut</sl-menu-item>
    <sl-menu-item value="copy">Copy</sl-menu-item>
    <sl-menu-item value="paste">Paste</sl-menu-item>
    <sl-divider></sl-divider>
    <sl-menu-item>
      Find
      <sl-menu slot="submenu">
        <sl-menu-item value="find">Find…</sl-menu-item>
        <sl-menu-item value="find-previous">Find Next</sl-menu-item>
        <sl-menu-item value="find-next">Find Previous</sl-menu-item>
      </sl-menu>
    </sl-menu-item>
    <sl-menu-item>
      Transformations
      <sl-menu slot="submenu">
        <sl-menu-item value="uppercase">Make uppercase</sl-menu-item>
        <sl-menu-item value="lowercase">Make lowercase</sl-menu-item>
        <sl-menu-item value="capitalize">Capitalize</sl-menu-item>
      </sl-menu>
    </sl-menu-item>
  </sl-menu>
</sl-dropdown>

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, which is usually the viewport unless an ancestor uses a transform, perspective, or filter. Refer to this page for more details.

<div class="dropdown-hoist">
  <sl-dropdown>
    <sl-button slot="trigger" caret>No Hoist</sl-button>
    <sl-menu>
      <sl-menu-item>Item 1</sl-menu-item>
      <sl-menu-item>Item 2</sl-menu-item>
      <sl-menu-item>Item 3</sl-menu-item>
    </sl-menu>
  </sl-dropdown>

  <sl-dropdown hoist>
    <sl-button slot="trigger" caret>Hoist</sl-button>
    <sl-menu>
      <sl-menu-item>Item 1</sl-menu-item>
      <sl-menu-item>Item 2</sl-menu-item>
      <sl-menu-item>Item 3</sl-menu-item>
    </sl-menu>
  </sl-dropdown>
</div>

<style>
  .dropdown-hoist {
    position: relative;
    border: solid 2px var(--sl-panel-border-color);
    padding: var(--sl-spacing-medium);
    overflow: hidden;
  }
</style>
div.dropdown-hoist
  sl-dropdown
    sl-button slot="trigger" caret=true No Hoist
    sl-menu
      sl-menu-item Item 1
      sl-menu-item Item 2
      sl-menu-item Item 3
  sl-dropdown hoist=true
    sl-button slot="trigger" caret=true Hoist
    sl-menu
      sl-menu-item Item 1
      sl-menu-item Item 2
      sl-menu-item Item 3

css:
  .dropdown-hoist {
    position: relative;
    border: solid 2px var(--sl-panel-border-color);
    padding: var(--sl-spacing-medium);
    overflow: hidden;
  }

Component Props

Property Default Details
open false

boolean

Indicates whether or not the dropdown is open. You can toggle this attribute to show and hide the dropdown, or you can use the show() and hide() methods and this attribute will reflect the dropdown’s open state.

placement 'bottom-start'

'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end'

The preferred placement of the dropdown panel. Note that the actual placement may vary as needed to keep the panel inside of the viewport.

disabled false

boolean

Disables the dropdown so the panel will not open.

stayOpenOnSelect
stay-open-on-select
false

boolean

By default, the dropdown is closed when an item is selected. This attribute will keep it open instead. Useful for dropdowns that allow for multiple interactions.

containingElement

HTMLElement | undefined

The dropdown will close when the user interacts outside of this element (e.g. clicking). Useful for composing other components that use a dropdown internally.

distance 0

number

The distance in pixels from which to offset the panel away from its trigger.

skidding 0

number

The distance in pixels from which to offset the panel along its trigger.

hoist false

boolean

Enable this option to prevent the panel from being clipped when the component is placed inside a container with overflow: auto|scroll. Hoisting uses a fixed positioning strategy that works in many, but not all, scenarios.

updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Slots

Name Details
(default) The dropdown’s main content.
trigger The dropdown’s trigger, usually a <sl-button> element.

Learn more about using slots.

Events

Name Name Name React Event Details
sl-show sl-show sl-show onSlShow

Emitted when the dropdown opens.

sl-after-show sl-after-show sl-after-show onSlAfterShow

Emitted after the dropdown opens and all animations are complete.

sl-hide sl-hide sl-hide onSlHide

Emitted when the dropdown closes.

sl-after-hide sl-after-hide sl-after-hide onSlAfterHide

Emitted after the dropdown closes and all animations are complete.

Learn more about events.

Methods

Name Details
show()

Shows the dropdown panel.

hide()

Hides the dropdown panel

reposition()

Instructs the dropdown menu to reposition. Useful when the position or size of the trigger changes when the menu is activated.

Learn more about methods.

CSS Parts

Name Description
base The component’s base wrapper.
trigger The container that wraps the trigger.
panel The panel that gets shown when the dropdown is open.

Learn more about customizing CSS parts.

Animations

Name Description
dropdown.show The animation to use when showing the dropdown.
dropdown.hide The animation to use when hiding the dropdown.

Learn more about customizing animations.

Dependencies

This component automatically imports the following dependencies.

  • <sl-popup>