Morphos
Overlays

Dropdown

A contextual menu that appears anchored to a trigger, offering a list of selectable actions.

Interactive example

Installation

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

Import

import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem } from '@morphos/overlays'

Usage

@Component()
class MyComponent extends StatefulComponent {
  @State() dropdown = new Dropdown()

  render() {
    return (
      <>
        <DropdownTrigger dropdown={this.dropdown}>
          Actions
        </DropdownTrigger>
        <DropdownMenu dropdown={this.dropdown}>
          <DropdownItem dropdown={this.dropdown} label="Edit" value="edit" onSelect={() => console.log('edit')} />
          <DropdownItem dropdown={this.dropdown} label="Delete" value="delete" onSelect={() => console.log('delete')} />
          <DropdownItem dropdown={this.dropdown} label="Archive" value="archive" disabled />
        </DropdownMenu>
      </>
    )
  }
}

Dropdown, DropdownTrigger, DropdownMenu, and DropdownItem are also re-exported under the aliases Menu, MenuTrigger, MenuContent, and MenuItem — they are the exact same classes, just under more familiar names. There is no separate Menu implementation.

import { Menu, MenuTrigger, MenuContent, MenuItem } from '@morphos/overlays'

Compound components

ComponentDescription
DropdownRoot state manager. Owns open state, the active (keyboard-focused) item index, and the computed anchor position.
DropdownTrigger<button> that toggles the menu on click. Sets aria-haspopup="menu", aria-expanded, aria-controls, and data-open.
DropdownMenu<ul role="menu"> rendered into a Portal, positioned with position: fixed. Handles arrow-key navigation.
DropdownItem<li role="menuitem">. Selectable via click or Enter/Space. Registers itself with the Dropdown instance for keyboard navigation.

Props — Dropdown

PropTypeDefaultDescription
openbooleanControlled open state. When set, the consumer owns the state.
defaultOpenbooleanfalseInitial open state in uncontrolled mode.
onOpenChange(open: boolean) => voidCalled when the open state changes.
closeOnSelectbooleantrueWhether selecting an item closes the menu.
side"top" | "bottom" | "left" | "right""bottom"Which edge of the trigger the menu is placed against.
align"start" | "center" | "end""start"Alignment of the menu along the trigger's perpendicular axis.
sideOffsetnumber4Gap in pixels between the trigger and the menu.
childrenChildrenContent — typically DropdownTrigger and DropdownMenu.

Methods

MethodDescription
toggle()Opens the menu if closed, closes it if open.
openDropdown()Opens the menu, sets the active index to 0, and recomputes position. Emits onOpenChange(true).
closeDropdown()Closes the menu and resets the active index. Emits onOpenChange(false).
handleKeyDown(event)Handles ArrowDown / ArrowUp / Home / End / Escape / Tab — called internally by DropdownMenu's onKeyDown.

Props — DropdownTrigger

PropTypeDefaultDescription
dropdownDropdownThe Dropdown instance this trigger controls.
childrenChildrenThe trigger element content.
classstringCSS class.
idstringHTML id. Falls back to an auto-generated id.
aria-labelstringAccessible label for the trigger.

Props — DropdownMenu

PropTypeDefaultDescription
dropdownDropdownThe Dropdown instance this menu belongs to.
childrenChildrenDropdownItem elements.
classstringCSS class.
idstringHTML id. Falls back to an auto-generated id.
aria-labelstringAccessible label for the menu.
aria-labelledbystringID of the element that labels the menu. Falls back to the trigger's id.

Props — DropdownItem

PropTypeDefaultDescription
dropdownDropdownThe Dropdown instance this item belongs to.
valuestringUnique value identifier.
labelstringDisplay text, used when no children are passed.
disabledbooleanfalseDisables the item.
onSelect() => voidCalled when the item is selected.
childrenChildrenItem content. Falls back to label if omitted.
classstringCSS class.
idstringHTML id.

Keyboard navigation

KeyAction
ArrowDownMove the active index to the next item (wraps around)
ArrowUpMove the active index to the previous item (wraps around)
HomeMove the active index to the first item
EndMove the active index to the last item
Enter / SpaceSelect the focused item
EscapeClose the menu
TabClose the menu

data-* attributes

AttributeElementWhen present
data-openDropdownTriggerMenu is open
data-openDropdownMenu rootMenu is open
data-disabledDropdownItemdisabled is true

DropdownMenu renders with role="menu" and each DropdownItem renders with role="menuitem" inside a Portal. The menu's position is computed with computeAnchorPosition() from @morphos/core, using DropdownTrigger's bounding rect and the side/align/sideOffset props on Dropdown. Dropdown does not trap focus or lock scroll.

Styling example

.morphos-dropdown-menu {
  z-index: 100;
  min-width: 10rem;
  padding: var(--morphos-space-1);
  list-style: none;
  border: 1px solid var(--morphos-color-border);
  border-radius: var(--morphos-radius-md);
}

.morphos-dropdown-item {
  display: flex;
  justify-content: space-between;
  padding: var(--morphos-space-2) var(--morphos-space-3);
  border-radius: var(--morphos-radius-sm);
  cursor: pointer;
}

.morphos-dropdown-item[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

On this page