@biem/ui

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

dropdown-menu-default.tsx
import { Button } from "@biem/ui/components/ui/button";
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from "@biem/ui/components/ui/dropdown-menu";

export function DropdownMenuDefault() {
	return (
		<DropdownMenu>
			<DropdownMenuTrigger render={<Button variant="outline"/>}>Transfer</DropdownMenuTrigger>
			<DropdownMenuContent>
				<DropdownMenuItem>Add cases</DropdownMenuItem>
				<DropdownMenuItem>Duplicate</DropdownMenuItem>
				<DropdownMenuItem>Print labels</DropdownMenuItem>
			</DropdownMenuContent>
		</DropdownMenu>
	);
}

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.

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

Propopen
Typeboolean
Default–
DescriptionSets whether the dropdown menu is open and makes it controlled. Update it in onOpenChange.
PropdefaultOpen
Typeboolean
Defaultfalse
DescriptionOpens the dropdown menu at first render. The dropdown menu then tracks its open state itself.
ProponOpenChange
Type(open: boolean, eventDetails: MenuRootChangeEventDetails) => void
Default–
DescriptionRuns when users open or close the dropdown menu. It receives the open state that follows.
ProponOpenChangeComplete
Type(open: boolean) => void
Default–
DescriptionRuns after the dropdown menu has opened or closed and its animations have finished.
Propmodal
Typeboolean
Defaulttrue
DescriptionLocks 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.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from opening the dropdown menu. It disables the trigger and every item.
ProploopFocus
Typeboolean
Defaulttrue
DescriptionReturns focus to the first item when users move past the last one with the arrow keys.
ProphighlightItemOnHover
Typeboolean
Defaulttrue
DescriptionMoves the highlight to the item under the pointer. With false, only the keyboard moves the highlight.
Proporientation
Type"horizontal" | "vertical"
Default"vertical"
DescriptionSets 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.
PropcloseParentOnEsc
Typeboolean
Defaultfalse
DescriptionHas an effect only in a submenu, so set it on DropdownMenuSub.
ProptriggerId
Typestring | null
Default–
DescriptionSets the ID of the trigger that a controlled dropdown menu is associated with. A dropdown menu without open doesn't need it.
PropdefaultTriggerId
Typestring | null
Default–
DescriptionSets the ID of the trigger that the dropdown menu is associated with when defaultOpen opens it at first render.
Prophandle
TypeMenuHandle<Payload>
Default–
DescriptionConnects the dropdown menu with triggers that are rendered outside of it. Create the handle with Menu.createHandle() from @base-ui/react/menu.
PropactionsRef
TypeRefObject<MenuRootActions | null>
Default–
DescriptionReceives 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.
Propchildren
TypeReactNode | ((arg: { payload: Payload | undefined }) => ReactNode)
Default–
DescriptionHolds the parts of the dropdown menu. A function receives the payload of the trigger that opened the dropdown menu.
PropopenOnHover
Typeboolean
Default–
DescriptionOpens the dropdown menu when the pointer rests on the trigger, in addition to a press.
Propdelay
Typenumber
Default100
DescriptionSets how many milliseconds the pointer must rest on the trigger before the dropdown menu opens. It has an effect only with openOnHover.
PropcloseDelay
Typenumber
Default0
DescriptionSets how many milliseconds the dropdown menu stays open after the pointer has left it. It has an effect only with openOnHover.
Prophandle
TypeMenuHandle<Payload>
Default–
DescriptionConnects the trigger with a dropdown menu that it is rendered outside of. Pass the same handle to DropdownMenu.
Proppayload
TypePayload
Default–
DescriptionPasses a value to the dropdown menu when this trigger opens it. A function as children of DropdownMenu receives it.
Propid
Typestring
Default–
DescriptionSets the ID of the trigger element. triggerId and defaultTriggerId of DropdownMenu refer to it.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the trigger with another component.
PropnativeButton
Typeboolean
Defaulttrue
DescriptionDeclares whether the rendered element is a native button. Set it to false when render returns a different element.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from opening the dropdown menu with this trigger.
PropkeepMounted
Typeboolean
Defaultfalse
DescriptionKeeps 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.
Propcontainer
TypeHTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null
Default–
DescriptionSets 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the portal with another component.
Propside
Type"top" | "bottom" | "left" | "right" | "inline-end" | "inline-start"
Default"bottom"
DescriptionSets 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.
PropsideOffset
Typenumber | OffsetFunction
Default4
DescriptionSets 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.
Propalign
Type"start" | "center" | "end"
Default"start"
DescriptionSets where the content lines up with the trigger along the chosen side: at its start, its center or its end.
PropalignOffset
Typenumber | OffsetFunction
Default0
DescriptionMoves 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.
PropfinalFocus
Typeboolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void)
Default–
DescriptionDetermines 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the content with another component.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the group with another component.
Propinset
Typeboolean
Default–
DescriptionIndents the label so that it lines up with the text of items that start with an icon.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the label with another component.
Propvariant
Type"default" | "destructive"
Default"default"
DescriptionControls the color and semantic role of the item. "destructive" marks an action that deletes something or cannot be undone.
Propinset
Typeboolean
Default–
DescriptionIndents the item so that its text lines up with the text of items that start with an icon.
ProponClick
Type(event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void
Default–
DescriptionRuns when users choose the item with the pointer or the keyboard.
PropcloseOnClick
Typeboolean
Defaulttrue
DescriptionCloses the dropdown menu when users choose the item.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from choosing the item. The arrow keys still move to it.
Proplabel
Typestring
Default–
DescriptionSets 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the item with another component.
PropnativeButton
Typeboolean
Defaultfalse
DescriptionDeclares whether the rendered element is a native button. Set it to true when render returns a button.
Propchecked
Typeboolean
Default–
DescriptionSets whether the item is checked and makes it controlled. Update it in onCheckedChange.
PropdefaultChecked
Typeboolean
Defaultfalse
DescriptionChecks the item at first render. The item then tracks its state itself.
ProponCheckedChange
Type(checked: boolean, eventDetails: MenuCheckboxItemChangeEventDetails) => void
Default–
DescriptionRuns when users check or uncheck the item. It receives the state that follows.
Propinset
Typeboolean
Default–
DescriptionIndents the item so that its text lines up with the text of items that start with an icon.
ProponClick
Type(event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void
Default–
DescriptionRuns when users choose the item with the pointer or the keyboard.
PropcloseOnClick
Typeboolean
Defaultfalse
DescriptionCloses the dropdown menu when users check or uncheck the item.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from checking or unchecking the item. The arrow keys still move to it.
Proplabel
Typestring
Default–
DescriptionSets 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the item with another component.
PropnativeButton
Typeboolean
Defaultfalse
DescriptionDeclares whether the rendered element is a native button. Set it to true when render returns a button.
Propvalue
Typeany
Default–
DescriptionSets the value of the selected item and makes the radio group controlled. Update it in onValueChange.
PropdefaultValue
Typeany
Default–
DescriptionSets the value of the item that is selected at first render. The radio group then tracks the selection itself.
ProponValueChange
Type(value: any, eventDetails: MenuRadioGroupChangeEventDetails) => void
Default–
DescriptionRuns when users select an item. It receives the value of that item.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from selecting any item of the radio group.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the radio group with another component.
Propvalue
Typeany
Default–
DescriptionIdentifies the item in value and defaultValue of the radio group. Every radio item needs one.
Propinset
Typeboolean
Default–
DescriptionIndents the item so that its text lines up with the text of items that start with an icon.
ProponClick
Type(event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void
Default–
DescriptionRuns when users choose the item with the pointer or the keyboard.
PropcloseOnClick
Typeboolean
Defaultfalse
DescriptionCloses the dropdown menu when users select the item.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from selecting the item. The arrow keys still move to it.
Proplabel
Typestring
Default–
DescriptionSets 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the item with another component.
PropnativeButton
Typeboolean
Defaultfalse
DescriptionDeclares whether the rendered element is a native button. Set it to true when render returns a button.
Propopen
Typeboolean
Default–
DescriptionSets whether the submenu is open and makes it controlled. Update it in onOpenChange.
PropdefaultOpen
Typeboolean
Defaultfalse
DescriptionOpens the submenu at first render. The submenu then tracks its open state itself.
ProponOpenChange
Type(open: boolean, eventDetails: MenuSubmenuRootChangeEventDetails) => void
Default–
DescriptionRuns when users open or close the submenu. It receives the open state that follows.
ProponOpenChangeComplete
Type(open: boolean) => void
Default–
DescriptionRuns after the submenu has opened or closed and its animations have finished.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from opening the submenu.
ProploopFocus
Typeboolean
Defaulttrue
DescriptionReturns focus to the first item of the submenu when users move past the last one with the arrow keys.
ProphighlightItemOnHover
Typeboolean
Defaulttrue
DescriptionMoves the highlight to the item under the pointer. With false, only the keyboard moves the highlight.
Proporientation
Type"horizontal" | "vertical"
Default"vertical"
DescriptionSets 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.
PropcloseParentOnEsc
Typeboolean
Defaultfalse
DescriptionCloses the whole dropdown menu when users press Escape in the submenu. Without it, Escape closes only the submenu.
PropactionsRef
TypeRefObject<MenuRootActions | null>
Default–
DescriptionReceives 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.
Propinset
Typeboolean
Default–
DescriptionIndents the trigger so that its text lines up with the text of items that start with an icon.
PropopenOnHover
Typeboolean
Defaulttrue
DescriptionOpens the submenu when the pointer rests on the trigger. With false, users open it with a press or the keyboard.
Propdelay
Typenumber
Default100
DescriptionSets how many milliseconds the pointer must rest on the trigger before the submenu opens. It has an effect only with openOnHover.
PropcloseDelay
Typenumber
Default0
DescriptionSets how many milliseconds the submenu stays open after the pointer has left it. It has an effect only with openOnHover.
ProponClick
Type(event: BaseUIEvent<MouseEvent<HTMLDivElement>>) => void
Default–
DescriptionRuns when users press the trigger with the pointer or the keyboard.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from opening the submenu with this trigger.
Proplabel
Typestring
Default–
DescriptionSets 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the trigger with another component.
PropnativeButton
Typeboolean
Defaultfalse
DescriptionDeclares whether the rendered element is a native button. Set it to true when render returns a button.
Propside
Type"top" | "bottom" | "left" | "right" | "inline-end" | "inline-start"
Default"right"
DescriptionSets 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.
PropsideOffset
Typenumber | OffsetFunction
Default0
DescriptionSets 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.
Propalign
Type"start" | "center" | "end"
Default"start"
DescriptionSets where the content lines up with the submenu trigger along the chosen side: at its start, its center or its end.
PropalignOffset
Typenumber | OffsetFunction
Default-3
DescriptionMoves 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.
PropfinalFocus
Typeboolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void)
Default–
DescriptionDetermines 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.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the content with another component.
Proporientation
Type"horizontal" | "vertical"
Default"horizontal"
DescriptionSets the orientation that the separator reports to assistive technology. The line itself stays horizontal.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the separator with another component.

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.