Dropdown Menu
A menu of actions and options that users open from a trigger.
A dropdown menu keeps actions and options behind a trigger and shows them when users open it. Users move through the items with the pointer or the arrow keys, and the menu closes when they choose an item, press Escape or press outside of it. Checkbox and radio items keep the menu open, so users can change several options in a row. The trigger has no styles of its own, so the examples render it as a Button, and the content is as wide as its trigger but at least 8rem. A label names a group for assistive technology and therefore only works inside a DropdownMenuGroup or a DropdownMenuRadioGroup.
Usage
Examples
With Label
Actions in a menu often refer to one particular object, such as a single order or a store. A label names the group of items that belong to it, and assistive technology announces that name with the items, so users know what their choice will affect.
With Separator
When a menu mixes actions of different kinds, such as editing an order and passing it on to another team, users scan it faster if related actions stay together. Separators divide the items into such groups, and assistive technology recognizes each one as a division, so the structure holds for every user.
With Icon
In menus that users open many times a day, an icon lets them recognize a familiar action before they read its name. The text still names the outcome, so every action remains clear where an icon alone would leave room for doubt.
With Shortcut
Frequent actions are faster on the keyboard than through a menu. Shown with an item, a shortcut teaches users its key combination every time they open the menu. On its own, the hint triggers nothing, so the application provides the key binding itself.
With Checkbox Items
Some settings consist of independent options, such as the figures a report includes. Checkbox items let users turn each option on or off, and the menu stays open after every change, so they adjust several options in a row. Through defaultChecked an item starts checked and then keeps its state on its own.
With Radio Group
A choice can also be exclusive, such as the order in which a list is sorted. In a radio group, users select exactly one item, and the menu stays open so they see the new selection at once. With defaultValue, the group begins with one item selected.
With Submenu
Actions that come in several variants would crowd the first level of a menu. A submenu gathers the variants behind one item, which users open by resting the pointer on it or with the keyboard. Escape then closes only the submenu, so users return to the first level without starting over.
Destructive
Cancelling an order or removing a store from a region often cannot be undone. Set to "destructive", variant marks such an item, so users recognize the consequence before they choose it and can still decide against it.
Inset
Once some items in a menu start with an icon, the text of the others no longer lines up with theirs. Through inset, an item or a label is indented to the same starting point, so users read every entry along one straight edge.
Item as Link
Navigation menus lead users to other pages instead of acting on the current one. With render, an item becomes a real link, so the browser handles the address and users can open the page in a new tab as well.
Top Side
Near the lower edge of a screen, such as in a toolbar below a table, a menu finds more room above its trigger. Once side is set to "top", the content opens there, and it moves to the opposite side when space runs short.
Right Side
A trigger in a narrow sidebar has more room beside it than below it. The content opens toward that room when side is set to "right", and it falls back to the left when the screen lacks the space.
Bottom Side
In most places, users expect a menu to open below its trigger, in the direction they read. This is the default, and side set to "bottom" states it explicitly; where the space below runs short, the content opens above instead.
Left Side
Row actions at the end of a table sit close to the right edge of the screen. Set to "left", side opens the content toward the table, and the content changes to the right side only when too little space remains on the left.
Open on Hover
In a navigation bar, users move across several menus and expect each one to open as soon as the pointer rests on it. Through openOnHover, the trigger responds after a short pause of the pointer, while a press still works. A menu opened this way is never modal, so the rest of the page stays usable.
Controlled
Certain workflows open a menu from elsewhere in the interface, such as a key that brings up the actions of the selected row. With open and onOpenChange, the application holds the open state, so the menu opens and closes whenever the workflow requires it, not only through its trigger.
Controlled Checkbox Items
When the options in a menu shape the screen around it, such as the filters of a list, the application needs every change at once. Through checked and onCheckedChange it holds the state of each item, so the list follows every change and the choice can be saved for the next visit.
Controlled Radio Group
A selection can also come from outside the menu, such as a sort order that users saved on their last visit. By holding the selected item through value and onValueChange, the application restores that choice and lets the rest of the screen react to every new one.
Disabled
While data is still loading, or when users lack the permission for these actions, the menu offers nothing they can use. Set on the menu itself, disabled prevents users from opening it and turns off the trigger as well as every item.
Disabled Item
A single action can be unavailable while the others remain useful, such as approving an order that still lacks a quantity. Marked as disabled, the item no longer reacts to a press, yet the arrow keys still reach it, so keyboard users learn that the action exists.
Disabled Radio Group
Once an order has shipped, the options chosen for it are settled. With disabled on the radio group, users still see the current selection but can no longer change it, and the arrow keys still move through its items.
API Reference
DropdownMenu
| Prop | open |
|---|---|
| Type | boolean |
| Default | – |
| Description | Sets whether the dropdown menu is open and makes it controlled. Update it in onOpenChange. |
| Prop | defaultOpen |
|---|---|
| Type | boolean |
| Default | false |
| Description | Opens the dropdown menu at first render. The dropdown menu then tracks its open state itself. |
| Prop | onOpenChange |
|---|---|
| Type | (open: boolean, eventDetails: MenuRootChangeEventDetails) => void |
| Default | – |
| Description | Runs when users open or close the dropdown menu. It receives the open state that follows. |
| Prop | onOpenChangeComplete |
|---|---|
| Type | (open: boolean) => void |
| Default | – |
| Description | Runs after the dropdown menu has opened or closed and its animations have finished. |
| Prop | modal |
|---|---|
| Type | boolean |
| Default | true |
| Description | Locks the page while the dropdown menu is open: the page doesn't scroll, and elements outside of the menu don't react to the pointer. Set it to false to keep the rest of the page usable. A dropdown menu that users open by hover is never modal. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the dropdown menu. It disables the trigger and every item. |
| Prop | loopFocus |
|---|---|
| Type | boolean |
| Default | true |
| Description | Returns focus to the first item when users move past the last one with the arrow keys. |
| Prop | highlightItemOnHover |
|---|---|
| Type | boolean |
| Default | true |
| Description | Moves the highlight to the item under the pointer. With false, only the keyboard moves the highlight. |
| Prop | orientation |
|---|---|
| Type | "horizontal" | "vertical" |
| Default | "vertical" |
| Description | Sets the arrow keys that move through the items: up and down for "vertical", left and right for "horizontal". It doesn't change the layout of the items. |
| Prop | closeParentOnEsc |
|---|---|
| Type | boolean |
| Default | false |
| Description | Has an effect only in a submenu, so set it on DropdownMenuSub. |
| Prop | triggerId |
|---|---|
| Type | string | null |
| Default | – |
| Description | Sets the ID of the trigger that a controlled dropdown menu is associated with. A dropdown menu without open doesn't need it. |
| Prop | defaultTriggerId |
|---|---|
| Type | string | null |
| Default | – |
| Description | Sets the ID of the trigger that the dropdown menu is associated with when defaultOpen opens it at first render. |
| Prop | handle |
|---|---|
| Type | MenuHandle<Payload> |
| Default | – |
| Description | Connects the dropdown menu with triggers that are rendered outside of it. Create the handle with Menu.createHandle() from @base-ui/react/menu. |
| Prop | actionsRef |
|---|---|
| Type | RefObject<MenuRootActions | null> |
| Default | – |
| Description | Receives the functions close and unmount. close closes the dropdown menu from code, and unmount removes it from the DOM after a closing animation that the code controls itself. |
| Prop | children |
|---|---|
| Type | ReactNode | ((arg: { payload: Payload | undefined }) => ReactNode) |
| Default | – |
| Description | Holds the parts of the dropdown menu. A function receives the payload of the trigger that opened the dropdown menu. |
DropdownMenuTrigger
| Prop | openOnHover |
|---|---|
| Type | boolean |
| Default | – |
| Description | Opens the dropdown menu when the pointer rests on the trigger, in addition to a press. |
| Prop | delay |
|---|---|
| Type | number |
| Default | 100 |
| Description | Sets how many milliseconds the pointer must rest on the trigger before the dropdown menu opens. It has an effect only with openOnHover. |
| Prop | closeDelay |
|---|---|
| Type | number |
| Default | 0 |
| Description | Sets how many milliseconds the dropdown menu stays open after the pointer has left it. It has an effect only with openOnHover. |
| Prop | handle |
|---|---|
| Type | MenuHandle<Payload> |
| Default | – |
| Description | Connects the trigger with a dropdown menu that it is rendered outside of. Pass the same handle to DropdownMenu. |
| Prop | payload |
|---|---|
| Type | Payload |
| Default | – |
| Description | Passes a value to the dropdown menu when this trigger opens it. A function as children of DropdownMenu receives it. |
| Prop | id |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the ID of the trigger element. triggerId and defaultTriggerId of DropdownMenu refer to it. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the trigger with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | true |
| Description | Declares whether the rendered element is a native button. Set it to false when render returns a different element. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the dropdown menu with this trigger. |
DropdownMenuPortal
| Prop | keepMounted |
|---|---|
| Type | boolean |
| Default | false |
| Description | Keeps the portal in the DOM while the dropdown menu is closed. DropdownMenuContent renders a portal of its own, so the content still leaves the DOM. |
| Prop | container |
|---|---|
| Type | HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null |
| Default | – |
| Description | Sets the element that the portal is rendered into. Without it, the portal is appended to the body. A DropdownMenuContent inside the portal is rendered there as well. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the portal with another component. |
DropdownMenuContent
| Prop | side |
|---|---|
| Type | "top" | "bottom" | "left" | "right" | "inline-end" | "inline-start" |
| Default | "bottom" |
| Description | Sets the side of the trigger that the content opens on. "inline-start" and "inline-end" follow the reading direction. The content moves to the opposite side when the chosen one has too little space. |
| Prop | sideOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | 4 |
| Description | Sets the distance between the trigger and the content in pixels. A function receives the side, the alignment and the dimensions of the trigger and the content, and returns the distance. |
| Prop | align |
|---|---|
| Type | "start" | "center" | "end" |
| Default | "start" |
| Description | Sets where the content lines up with the trigger along the chosen side: at its start, its center or its end. |
| Prop | alignOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | 0 |
| Description | Moves the content along the alignment axis by a number of pixels. A function receives the same data as the one for sideOffset and returns the offset. |
| Prop | finalFocus |
|---|---|
| Type | boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void) |
| Default | – |
| Description | Determines the element that receives focus when the dropdown menu closes. Without it, focus returns to the trigger or to the element that had focus before. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the content with another component. |
DropdownMenuGroup
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the group with another component. |
DropdownMenuLabel
| Prop | inset |
|---|---|
| Type | boolean |
| Default | – |
| Description | Indents the label so that it lines up with the text of items that start with an icon. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the label with another component. |
DropdownMenuItem
| Prop | variant |
|---|---|
| Type | "default" | "destructive" |
| Default | "default" |
| Description | Controls the color and semantic role of the item. "destructive" marks an action that deletes something or cannot be undone. |
| Prop | inset |
|---|---|
| Type | boolean |
| Default | – |
| Description | Indents the item so that its text lines up with the text of items that start with an icon. |
| Prop | onClick |
|---|---|
| Type | (event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void |
| Default | – |
| Description | Runs when users choose the item with the pointer or the keyboard. |
| Prop | closeOnClick |
|---|---|
| Type | boolean |
| Default | true |
| Description | Closes the dropdown menu when users choose the item. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from choosing the item. The arrow keys still move to it. |
| Prop | label |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the text that the item is matched against when users type to jump to an item. Without it, the item is matched against its text content. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the item with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | false |
| Description | Declares whether the rendered element is a native button. Set it to true when render returns a button. |
DropdownMenuCheckboxItem
| Prop | checked |
|---|---|
| Type | boolean |
| Default | – |
| Description | Sets whether the item is checked and makes it controlled. Update it in onCheckedChange. |
| Prop | defaultChecked |
|---|---|
| Type | boolean |
| Default | false |
| Description | Checks the item at first render. The item then tracks its state itself. |
| Prop | onCheckedChange |
|---|---|
| Type | (checked: boolean, eventDetails: MenuCheckboxItemChangeEventDetails) => void |
| Default | – |
| Description | Runs when users check or uncheck the item. It receives the state that follows. |
| Prop | inset |
|---|---|
| Type | boolean |
| Default | – |
| Description | Indents the item so that its text lines up with the text of items that start with an icon. |
| Prop | onClick |
|---|---|
| Type | (event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void |
| Default | – |
| Description | Runs when users choose the item with the pointer or the keyboard. |
| Prop | closeOnClick |
|---|---|
| Type | boolean |
| Default | false |
| Description | Closes the dropdown menu when users check or uncheck the item. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from checking or unchecking the item. The arrow keys still move to it. |
| Prop | label |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the text that the item is matched against when users type to jump to an item. Without it, the item is matched against its text content. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the item with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | false |
| Description | Declares whether the rendered element is a native button. Set it to true when render returns a button. |
DropdownMenuRadioGroup
| Prop | value |
|---|---|
| Type | any |
| Default | – |
| Description | Sets the value of the selected item and makes the radio group controlled. Update it in onValueChange. |
| Prop | defaultValue |
|---|---|
| Type | any |
| Default | – |
| Description | Sets the value of the item that is selected at first render. The radio group then tracks the selection itself. |
| Prop | onValueChange |
|---|---|
| Type | (value: any, eventDetails: MenuRadioGroupChangeEventDetails) => void |
| Default | – |
| Description | Runs when users select an item. It receives the value of that item. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from selecting any item of the radio group. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the radio group with another component. |
DropdownMenuRadioItem
| Prop | value |
|---|---|
| Type | any |
| Default | – |
| Description | Identifies the item in value and defaultValue of the radio group. Every radio item needs one. |
| Prop | inset |
|---|---|
| Type | boolean |
| Default | – |
| Description | Indents the item so that its text lines up with the text of items that start with an icon. |
| Prop | onClick |
|---|---|
| Type | (event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void |
| Default | – |
| Description | Runs when users choose the item with the pointer or the keyboard. |
| Prop | closeOnClick |
|---|---|
| Type | boolean |
| Default | false |
| Description | Closes the dropdown menu when users select the item. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from selecting the item. The arrow keys still move to it. |
| Prop | label |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the text that the item is matched against when users type to jump to an item. Without it, the item is matched against its text content. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the item with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | false |
| Description | Declares whether the rendered element is a native button. Set it to true when render returns a button. |
DropdownMenuSub
| Prop | open |
|---|---|
| Type | boolean |
| Default | – |
| Description | Sets whether the submenu is open and makes it controlled. Update it in onOpenChange. |
| Prop | defaultOpen |
|---|---|
| Type | boolean |
| Default | false |
| Description | Opens the submenu at first render. The submenu then tracks its open state itself. |
| Prop | onOpenChange |
|---|---|
| Type | (open: boolean, eventDetails: MenuSubmenuRootChangeEventDetails) => void |
| Default | – |
| Description | Runs when users open or close the submenu. It receives the open state that follows. |
| Prop | onOpenChangeComplete |
|---|---|
| Type | (open: boolean) => void |
| Default | – |
| Description | Runs after the submenu has opened or closed and its animations have finished. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the submenu. |
| Prop | loopFocus |
|---|---|
| Type | boolean |
| Default | true |
| Description | Returns focus to the first item of the submenu when users move past the last one with the arrow keys. |
| Prop | highlightItemOnHover |
|---|---|
| Type | boolean |
| Default | true |
| Description | Moves the highlight to the item under the pointer. With false, only the keyboard moves the highlight. |
| Prop | orientation |
|---|---|
| Type | "horizontal" | "vertical" |
| Default | "vertical" |
| Description | Sets the arrow keys that move through the items of the submenu: up and down for "vertical", left and right for "horizontal". It doesn't change the layout of the items. |
| Prop | closeParentOnEsc |
|---|---|
| Type | boolean |
| Default | false |
| Description | Closes the whole dropdown menu when users press Escape in the submenu. Without it, Escape closes only the submenu. |
| Prop | actionsRef |
|---|---|
| Type | RefObject<MenuRootActions | null> |
| Default | – |
| Description | Receives the functions close and unmount. close closes the submenu from code, and unmount removes it from the DOM after a closing animation that the code controls itself. |
DropdownMenuSubTrigger
| Prop | inset |
|---|---|
| Type | boolean |
| Default | – |
| Description | Indents the trigger so that its text lines up with the text of items that start with an icon. |
| Prop | openOnHover |
|---|---|
| Type | boolean |
| Default | true |
| Description | Opens the submenu when the pointer rests on the trigger. With false, users open it with a press or the keyboard. |
| Prop | delay |
|---|---|
| Type | number |
| Default | 100 |
| Description | Sets how many milliseconds the pointer must rest on the trigger before the submenu opens. It has an effect only with openOnHover. |
| Prop | closeDelay |
|---|---|
| Type | number |
| Default | 0 |
| Description | Sets how many milliseconds the submenu stays open after the pointer has left it. It has an effect only with openOnHover. |
| Prop | onClick |
|---|---|
| Type | (event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void |
| Default | – |
| Description | Runs when users press the trigger with the pointer or the keyboard. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the submenu with this trigger. |
| Prop | label |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the text that the trigger is matched against when users type to jump to an item. Without it, the trigger is matched against its text content. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the trigger with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | false |
| Description | Declares whether the rendered element is a native button. Set it to true when render returns a button. |
DropdownMenuSubContent
| Prop | side |
|---|---|
| Type | "top" | "bottom" | "left" | "right" | "inline-end" | "inline-start" |
| Default | "right" |
| Description | Sets the side of the submenu trigger that the content opens on. "inline-start" and "inline-end" follow the reading direction. The content moves to another side when the chosen one has too little space. |
| Prop | sideOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | 0 |
| Description | Sets the distance between the submenu trigger and the content in pixels. A function receives the side, the alignment and the dimensions of the trigger and the content, and returns the distance. |
| Prop | align |
|---|---|
| Type | "start" | "center" | "end" |
| Default | "start" |
| Description | Sets where the content lines up with the submenu trigger along the chosen side: at its start, its center or its end. |
| Prop | alignOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | -3 |
| Description | Moves the content along the alignment axis by a number of pixels. A function receives the same data as the one for sideOffset and returns the offset. |
| Prop | finalFocus |
|---|---|
| Type | boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void) |
| Default | – |
| Description | Determines the element that receives focus when the submenu closes. Without it, focus returns to the submenu trigger or to the element that had focus before. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the content with another component. |
DropdownMenuSeparator
| Prop | orientation |
|---|---|
| Type | "horizontal" | "vertical" |
| Default | "horizontal" |
| Description | Sets the orientation that the separator reports to assistive technology. The line itself stays horizontal. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the separator with another component. |
DropdownMenuShortcut
DropdownMenuShortcut shows the keyboard shortcut of an item at the end of its row and doesn't handle the key press itself. It renders a span and has no props of its own.