Skip to Content
ComponentsDropdownMenu

DropdownMenu

Display a dropdown menu.

Documentation

Usage

Use the DropdownMenu, DropdownMenuTrigger, and DropdownMenuContent components to build out menus.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Controlled

Use the open and defaultOpen props to toggle between controlled and uncontrolled usage. And combine it with onOpenChange to listen for changes to the state.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Flex, Switch, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; import { useState } from "react"; export function App() { const [keepOpen, setKeepOpen] = useState(false); const [open, setOpen] = useState(false); return ( <Flex flexDirection="row"> <Switch onCheckedChange={setKeepOpen}>Keep menu open</Switch> <DropdownMenu modal={false} onOpenChange={(flag) => setOpen(flag || keepOpen)} open={open} > <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </Flex> ); }

Non modal usage

By default scrolling and interactions with outside elements is disabled when menu is open. Set modal prop to false in order to render a non-modal dropdown.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu modal={false}> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Trigger

Customize trigger

By default we use the Button component for the menu trigger which accepts all of the existing button props.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconFilter, IconLogout, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger appearance="subtle" aria-label="Filters" icon={<IconFilter />} /> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Ellipsis trigger

We can also use asChild to render a completely different component. We provide two built-in buttons:

  • AngleMenuButton (default)
  • EllipsisMenuButton
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EllipsisMenuButton, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger asChild> <EllipsisMenuButton appearance="subtle" aria-label="My Account" /> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Content

Menu position

Use the align and side props on DropdownMenuContent to change the default position of the dropdown.

import type { ComponentPropsWithRef } from "react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; export function App({ align, side, }: Pick<ComponentPropsWithRef<typeof DropdownMenuContent>, "align" | "side">) { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent align={align} side={side}> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Item

Appearance

Use the intent prop to control the appearance of items.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconPencil, IconTrash } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem icon={<IconPencil />}>Edit</DropdownMenuItem> <DropdownMenuItem icon={<IconTrash />} intent="danger"> Delete </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Description

Use the description prop to add secondary text to items.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Actions</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem description="Create a new task"> New task </DropdownMenuItem> <DropdownMenuItem description="Copy this task"> Copy task </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem intent="danger">Delete task</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Disabled items

Use the disabled prop on menu items to disable them.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconLogout, IconUser, IconUsers } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuItem disabled icon={<IconUsers />}> Team Management </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Selection

Use the onSelect prop to handle selection of items.

Last selected item:

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Flex, Text, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; import { useState } from "react"; export function App() { const [selected, setSelected] = useState(""); return ( <Flex flexDirection="row"> <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />} onSelect={() => setSelected("view")} > View Profile </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />} onSelect={() => setSelected("logout")} > Logout </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> <Text>Last selected item: {selected}</Text> </Flex> ); }

Left and right addons

Use the icon, addonBefore, and addonAfter props to add icons, text, or any other element to the start or end of the menu items.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Kbd, } from "@optiaxiom/react"; import { IconLogout, IconSettings, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem addonAfter={ <Kbd keys={["option", "shift"]} variant="subtle"> P </Kbd> } icon={<IconSettings />} > Preferences </DropdownMenuItem> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem addonAfter={ <Kbd keys={["option", "shift"]} variant="subtle"> Q </Kbd> } icon={<IconLogout />} > Logout </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

CheckboxItem

Use the DropdownMenuCheckboxItem component to render a checkbox and add the checked and onCheckedChange props to control the state.

import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuTrigger, } from "@optiaxiom/react"; import { useState } from "react"; export function App() { const [showStatus, setShowStatus] = useState(false); const [showNotification, setShowNotification] = useState(false); return ( <DropdownMenu> <DropdownMenuTrigger>Profile</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>Display Options</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showStatus} onCheckedChange={setShowStatus} > Show Status </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showNotification} onCheckedChange={setShowNotification} > Show Notifications </DropdownMenuCheckboxItem> </DropdownMenuContent> </DropdownMenu> ); }

Label

Use the DropdownMenuLabel component to render a read-only label.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconLogout, IconUser } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem icon={<IconUser />}>View Profile</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem icon={<IconLogout />}>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Submenus

Use DropdownMenuSub, DropdownMenuSubTrigger, and DropdownMenuSubContent to render a submenus.

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@optiaxiom/react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Profile</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Profile</DropdownMenuLabel> <DropdownMenuSub> <DropdownMenuSubTrigger>Settings</DropdownMenuSubTrigger> <DropdownMenuSubContent> <DropdownMenuItem>Privacy</DropdownMenuItem> <DropdownMenuItem>Security</DropdownMenuItem> <DropdownMenuItem>Policy</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuSub> <DropdownMenuSeparator /> <DropdownMenuItem>Logout</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ); }

Dialogs inside menus

Combine dropdown menus with dialog to show alerts when selecting an item.

Make sure to enable asChild prop on AlertDialogTrigger and call event.preventDefault() in the item onSelect handler.

import { AlertDialog, AlertDialogAction, AlertDialogBody, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@optiaxiom/react"; import { IconPencil, IconTrash } from "@tabler/icons-react"; export function App() { return ( <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem icon={<IconPencil />}>Edit</DropdownMenuItem> <AlertDialog> <AlertDialogTrigger asChild> <DropdownMenuItem icon={<IconTrash />} intent="danger" onSelect={(event) => event.preventDefault()} > Delete </DropdownMenuItem> </AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader>Are you sure?</AlertDialogHeader> <AlertDialogBody> The task and all content will be deleted. </AlertDialogBody> <AlertDialogFooter> <AlertDialogCancel /> <AlertDialogAction>Yes, delete</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> </DropdownMenuContent> </DropdownMenu> ); }

Related

Combobox

Multi-purpose combobox widget to allow selection from a dynamic set of options.

Select

Single select combobox widget to allow selection from a fixed set of options.

Props

DropdownMenu

Doesn't render its own HTML element.

Prop

defaultOpen

The initial open state in uncontrolled mode.

false | true

modal

When enabled interaction with outside elements will be disabled and only dropdown content will be visible to screen readers.

false | true

onOpenChange

Handler that is called when the open state changes.

(open: boolean) => void

open

The open state in controlled mode.

false | true

DropdownMenuTrigger

Supports all Button props in addition to its own. Renders a <button> element.

Prop

addonAfter

Display content inside the button after children.

ReactNode

addonBefore

Display content inside the button before children.

ReactNode

appearance

Control the appearance by selecting between the different button types.

"default" | "danger" | "primary" | "subtle" | "danger-outline" | "inverse"

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

disabled

Whether the button is disabled.

false | true

icon

Display an icon before or after the button content or omit children to only show the icon.

ReactNode

iconPosition

Control whether to show the icon before or after the button content.

"end" | "start"

loading

Whether to show loading spinner inside the button.

false | true

size

Control the size of the button.

"sm" | "md" | "lg"

square

Whether button should have square shape.

false | true

DropdownMenuContent

Supports all Box props in addition to its own. Renders a <div> element.

Prop

align

"center" | "end" | "start"

Default: start

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

loading

Whether to show loading spinner inside the menu.

false | true

maxH

Whether to restrict the max-height of the content.

Content is also restricted by the available height in the screen relative to the trigger.

"xs" | "sm" | "md" | "lg" | "full"

minW

Whether to set the min-width to the width of the trigger.

"0" | "trigger"

onCloseAutoFocus

Event handler called when auto-focusing on close. Can be prevented.

(event: Event) => void

onEscapeKeyDown

(event: KeyboardEvent) => void

onFocusOutside

(event: FocusOutsideEvent) => void

onInteractOutside

(event: FocusOutsideEvent | PointerDownOutsideEvent) => void

onPointerDownOutside

(event: PointerDownOutsideEvent) => void

side

"bottom" | "left" | "right" | "top"

DropdownMenuItem

Supports all Box props in addition to its own. Renders a <div> element.

Prop

addonAfter

Display content inside the item after children.

ReactNode

addonBefore

Display content inside the item before children.

ReactNode

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

description

Add secondary text after the primary label.

ReactNode

disabled

false | true

icon

Display an icon before the item content.

ReactNode

intent

Control the appearance by selecting between the different item types.

"danger" | "neutral"

onSelect

(event: Event) => void

textValue

string

DropdownMenuCheckboxItem

Supports all Box props in addition to its own. Renders a <div> element.

Prop

addonAfter

Display content inside the item after children.

ReactNode

addonBefore

Display content inside the item before children.

ReactNode

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

checked

false | true | "indeterminate"

className

string

description

Add secondary text after the primary label.

ReactNode

disabled

false | true

icon

Display an icon before the item content.

ReactNode

intent

Control the appearance by selecting between the different item types.

"danger" | "neutral"

onCheckedChange

(checked: boolean) => void

onSelect

(event: Event) => void

textValue

string

DropdownMenuLabel

Supports all Box props in addition to its own. Renders a <div> element.

Prop

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

DropdownMenuGroup

Supports all Box props in addition to its own. Renders a <div> element.

Prop

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

DropdownMenuSeparator

Supports all Separator props in addition to its own. Renders a <div> element.

Prop

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

DropdownMenuSub

Doesn't render its own HTML element.

Prop

defaultOpen

The initial open state in uncontrolled mode.

false | true

onOpenChange

Handler that is called when the open state changes.

(open: boolean) => void

open

The open state in controlled mode.

false | true

DropdownMenuSubTrigger

Supports all Box props in addition to its own. Renders a <div> element.

Prop

addonAfter

Display content inside the item after children.

ReactNode

addonBefore

Display content inside the item before children.

ReactNode

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

description

Add secondary text after the primary label.

ReactNode

disabled

false | true

icon

Display an icon before the item content.

ReactNode

intent

Control the appearance by selecting between the different item types.

"danger" | "neutral"

textValue

string

DropdownMenuSubContent

Supports all Box props in addition to its own. Renders a <div> element.

Prop

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

maxH

Whether to restrict the max-height of the content.

Content is also restricted by the available height in the screen relative to the trigger.

"xs" | "sm" | "md" | "lg" | "full"

minW

Whether to set the min-width to the width of the trigger.

"0" | "trigger"

onEscapeKeyDown

(event: KeyboardEvent) => void

onFocusOutside

(event: FocusOutsideEvent) => void

onInteractOutside

(event: FocusOutsideEvent | PointerDownOutsideEvent) => void

onPointerDownOutside

(event: PointerDownOutsideEvent) => void

Changelog

0.1.0

  • Added component
Last updated on