DropdownMenu
DropdownMenu renders a dropdown menu based on Base UI Menu primitives, aligned with ContextMenu item layout and styling.
import { DropdownMenu } from '@lobehub/ui/base-ui';Default
Keep Open on Item Click
Standard items close the menu after a click. Set closeOnClick: false on an item when the menu should remain open while its action runs. This behavior applies at any nesting level, including submenu items.
Atom Components
Exported primitives can be composed to build custom dropdown menus.
Submenu
ActionIcon Trigger With Submenu
Group
Header & Footer
Use the header and footer props to pin custom content above and below the scrollable items area. Both slots carry a divider border. Slot content is not a menu item: it is not keyboard-navigable, and clicking it does not close the menu — close the menu from a slot through the controlled open prop.
When the menu is taller than its max-height, the items area scrolls while the header and footer stay pinned. Constrain the height through popupProps.style.
Icon Space Mode
Control how icon spacing is reserved across menu items. In global mode (default), if any item has an icon, all items reserve icon space. In group mode, only groups containing icons reserve icon space.
Description
Items can display a secondary description below the label using the desc property.
Icon Align
When items have descriptions, use iconAlign to control icon vertical alignment. center (default) vertically centers the icon, start aligns it with the first line of text.
Danger
Open on Hover
Checkbox Items
Switch Items
Lazy Items
Virtual List
Long flat lists (a branch picker, a model list) can be virtualized so only the rows near the scroll position are mounted. Compose it from atoms: a DropdownMenuHeader holding a search input that filters the rows, a DropdownMenuScrollViewport with virtual and a listItemHeight hint wrapping the DropdownMenuItem rows, and a DropdownMenuFooter with the pinned action. The viewport is the only scroller — it renders through ScrollArea — while header and footer stay fixed. A DropdownMenuItem placed directly in a header or footer drops the slot's inline padding so it lines up with the rows. Keyboard navigation works across the full list — arrow keys, Home/End, and typeahead jump to any row, not just the mounted window — the highlighted row stays mounted while you scroll, and keepMounted pins extra child indices. The composed DropdownMenu accepts the same virtual / listItemHeight props for items-driven menus.
Custom Trigger (Non-button)
Link Label
Uploader
Tooltip Hover Stay
When using Tooltip inside DropdownMenu, wrap both in TooltipGroup to ensure the DropdownMenu stays open when hovering over the Tooltip content.
APIs
DropdownMenuV2
actionsRefMenuRootPropsReact.RefObject<MenuRootActions | null>A ref to imperative actions. - `unmount`: Manually unmounts the menu. Call this after any externally controlled closing animation finishes. - `close`: When specified, the menu can be closed imperatively.
childrenRequiredReactNodecloseParentOnEscMenuRootPropsbooleanWhen in a submenu, determines whether pressing the Escape key closes the entire menu, or only the current child menu.
Defaults to
false.defaultOpenMenuRootPropsbooleanWhether the menu is initially open. To render a controlled menu, use the `open` prop instead.
Defaults to
false.defaultTriggerIdMenuRootPropsnull | stringID of the trigger that the menu is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open menu.
disabledMenuRootPropsbooleanWhether the component should ignore user interaction.
Defaults to
false.footernull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>底部固定插槽,渲染于可滚动的 items 区域下方,自带分隔边框
handleMenuRootPropsMenuHandle<unknown>A handle to associate the menu with a trigger. If specified, allows external triggers to control the menu's open state.
headernull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>顶部固定插槽,渲染于可滚动的 items 区域上方,自带分隔边框
highlightItemOnHoverMenuRootPropsbooleanWhether moving the pointer over items should highlight them. Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state.
Defaults to
true.iconAlign'center' | 'start'图标与 label+desc 的垂直对齐方式 - 'center': 图标垂直居中(默认) - 'start': 图标与第一行文本顶部对齐,仅在 item 有 desc 时生效
Defaults to
'center'.iconSpaceMode'group' | 'global'图标空间保留模式 - 'global': 当任何一个选项有图标时,所有 item 都保留图标位 - 'group': 只有当一个分组中存在图标时,该分组才保留图标位
Defaults to
'global'.itemsRequiredBaseMenuItemType[] | (() => DropdownItem[])listItemHeightVirtualListPropsnumberRow height hint for the virtualizer; rows are still measured after mount.
loopFocusMenuRootPropsbooleanWhether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys.
Defaults to
true.modalMenuRootPropsbooleanDetermines if the menu enters a modal state when open. - `true`: user interaction is limited to the menu: document page scroll is locked and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior. Nested menus ignore this prop, and menus opened by hover are never modal.
Defaults to
true.nativeButtonbooleanonOpenChangeMenuRootProps(open: boolean, eventDetails: MenuRoot.ChangeEventDetails) => voidEvent handler called when the menu is opened or closed.
onOpenChangeCompleteMenuRootProps(open: boolean) => voidEvent handler called after any animations complete when the menu is opened or closed.
openMenuRootPropsbooleanWhether the menu is currently open.
orientationMenuRootProps'horizontal' | 'vertical'The visual orientation of the menu. Controls whether roving focus uses up/down or left/right arrow keys.
Defaults to
'vertical'.placement'bottom' | 'left' | 'right' | 'top' | 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight' | 'topCenter' | 'bottomCenter' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom'Defaults to
"bottomLeft".popupPropsMenuPopupPropsportalPropsMenuPortalPropspositionerPropsMenuPositionerPropstrigger'both' | 'click' | 'hover' | ('click' | 'hover')[]触发方式
Defaults to
"click".triggerIdMenuRootPropsnull | stringID of the trigger that the menu is associated with. This is useful in conjunction with the `open` prop to create a controlled menu. There's no need to specify this prop when the menu is uncontrolled (that is, when the `open` prop is not set).
triggerPropsOmit<MenuTriggerProps<unknown>, 'children'>virtualVirtualListPropsbooleanOnly mount the rows near the scroll position. Use for long flat lists (hundreds of rows); groups and submenus keep working but are kept mounted as one row.
Defaults to
false.
Additionally, DropdownMenuV2 inherits all properties from Base UI Menu.Root except children.
Menu Items
Menu items are the same as those used for Menu/Dropdown, with support for type: 'checkbox' and type: 'switch' items. See Menu for details on base item types.
Standard Item
| Property | Description | Type | Default |
|---|---|---|---|
| desc | Secondary description text displayed below the label | ReactNode | - |
| closeOnClick | Close menu on click. Set to false for items with Upload or file picker elements. | boolean | true |
Checkbox Item
| Property | Description | Type | Default |
|---|---|---|---|
| type | Item type | 'checkbox' | - |
| checked | Controlled checked state | boolean | - |
| defaultChecked | Uncontrolled initial state | boolean | false |
| onCheckedChange | Checked change handler | (checked: boolean) => void | - |
| closeOnClick | Close menu on toggle | boolean | false |
Switch Item
| Property | Description | Type | Default |
|---|---|---|---|
| type | Item type | 'switch' | - |
| checked | Controlled checked state | boolean | - |
| defaultChecked | Uncontrolled initial state | boolean | false |
| onCheckedChange | Checked change handler | (checked: boolean) => void | - |
| closeOnClick | Close menu on toggle | boolean | false |