Free and open-source React context menu components built for modern applications and websites. Trigger these menus with a right-click, long-press, or the keyboard menu key, built using React Aria and styled with Tailwind CSS.
Installation
Context menus reuse the same Dropdown component as our dropdown menus — only the trigger changes. You can add it using our CLI or manually:
npx untitledui@latest add dropdown
Context menu examples
Below are examples and variations of this context menu component. Right-click (or long-press on touch) the highlighted area to open the menu.
API reference
Import the parts and assemble them:
import { Dropdown } from "@/components/base/dropdown/dropdown"; <Dropdown.Popover> <Dropdown.Menu> <Dropdown.Item /> <Dropdown.Item /> <Dropdown.Separator /> <Dropdown.Item /> </Dropdown.Menu> </Dropdown.Popover>
Dropdown.DotsButton
Renders React Aria’s Button — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
onClick | ((e: MouseEvent<FocusableElement>) => void) | — | Not recommended – use onPress instead. onClick is an alias for onPress provided for compatibility with other libraries. onPress provides additional event details for non-mouse interactions. |
onPress | ((e: PressEvent) => void) | — | Handler that is called when the press is released over the target. |
onPressChange | ((isPressed: boolean) => void) | — | Handler that is called when the press state changes. |
onPressEnd | ((e: PressEvent) => void) | — | Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target. |
onPressStart | ((e: PressEvent) => void) | — | Handler that is called when a press interaction starts. |
onPressUp | ((e: PressEvent) => void) | — | Handler that is called when a press is released over the target, regardless of whether it started on the target or not. |
onHoverChange | ((isHovering: boolean) => void) | — | Handler that is called when the hover state changes. |
onHoverEnd | ((e: HoverEvent) => void) | — | Handler that is called when a hover interaction ends. |
onHoverStart | ((e: HoverEvent) => void) | — | Handler that is called when a hover interaction starts. |
onBlur | ((e: FocusEvent<Element, Element>) => void) | — | Handler that is called when the element loses focus. |
onFocus | ((e: FocusEvent<Element, Element>) => void) | — | Handler that is called when the element receives focus. |
onFocusChange | ((isFocused: boolean) => void) | — | Handler that is called when the element's focus status changes. |
autoFocus | boolean | — | Whether the element should receive focus on render. |
excludeFromTabOrder | boolean | — | Whether to exclude the element from the sequential tab order. If true, the element will not be focusable via the keyboard by tabbing. This should be avoided except in rare scenarios where an alternative means of accessing the element or its functionality via the keyboard is available. |
onKeyDown | ((e: KeyboardEvent) => void) | — | Handler that is called when a key is pressed. |
onKeyUp | ((e: KeyboardEvent) => void) | — | Handler that is called when a key is released. |
form | string | — | The <form> element to associate the button with. The value of this attribute must be the id of a <form> in the same document. |
formAction | string | ((formData: FormData) => void | Promise<void>) | — | The URL that processes the information submitted by the button. Overrides the action attribute of the button's form owner. |
formEncType | string | — | Indicates how to encode the form data that is submitted. |
formMethod | string | — | Indicates the HTTP method used to submit the form. |
formNoValidate | boolean | — | Indicates that the form is not to be validated when it is submitted. |
formTarget | string | — | Overrides the target attribute of the button's form owner. |
id | string | — | The element's unique identifier. |
isDisabled | boolean | — | Whether the button is disabled. |
isPending | boolean | — | Whether the button is in a pending state. This disables press and hover events while retaining focusability, and announces the pending state to screen readers. |
name | string | — | Submitted as a pair with the button's value as part of the form data. |
preventFocusOnPress | boolean | — | Whether to prevent focus from moving to the button when pressing it.Caution, this can make the button inaccessible and should only be used when alternative keyboard interaction is provided, such as ComboBox's MenuTrigger or a NumberField's increment/decrement control. |
type | "button""submit""reset" | "button" | The behavior of the button when used in an HTML form. |
value | string | — | The value associated with the button's name when it's submitted with the form data. |
Styling (5)
| Prop | Type | Default | Description |
|---|---|---|---|
style | StyleOrFunction<ButtonRenderProps> | — | The inline style for the element. A function may be provided to compute the style based on component state. |
children | ChildrenOrFunction<ButtonRenderProps> | — | The children of the component. A function may be provided to alter the children based on component state. |
slot | string | null | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent. |
className | ClassNameOrFunction<ButtonRenderProps> | — | The CSS className for the element. A function may be provided to compute the class based on component state. |
render | DOMRenderFunction<"button", ButtonRenderProps> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
Accessibility (10)
| Prop | Type | Default | Description |
|---|---|---|---|
aria-describedby | string | — | Identifies the element (or elements) that describes the object. |
aria-details | string | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label | string | — | Defines a string value that labels the current element. |
aria-labelledby | string | — | Identifies the element (or elements) that labels the current element. |
aria-controls | string | — | Identifies the element (or elements) whose contents or presence are controlled by the current element. |
aria-current | falsetrue"true""false""page""step""location""date""time" | — | Indicates whether this element represents the current item within a container or set of related elements. |
aria-disabled | falsetrue"true""false" | — | Indicates whether the element is disabled to users of assistive technology. |
aria-expanded | falsetrue"true""false" | — | Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. |
aria-haspopup | falsetrue"true""false""menu""listbox""tree""grid""dialog" | — | Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. |
aria-pressed | falsetrue"true""false""mixed" | — | Indicates the current "pressed" state of toggle buttons. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
Dropdown.Item
Renders React Aria’s MenuItem — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The label of the item to be displayed. |
addon | string | — | An addon to be displayed on the right side of the item. |
unstyled | boolean | — | If true, the item will not have any styles. |
icon | FC<{ className?: string; }> | — | An icon to be displayed on the left side of the item. |
avatarUrl | string | — | Avatar URL to be displayed on the left side of the item. |
selectionIndicator | "checkmark""checkbox""radio""toggle""none" | "checkmark" | The selection indicator to be displayed on the item. |
Props from React Aria (31)
| Prop | Type | Default | Description |
|---|---|---|---|
onClick | ((e: MouseEvent<FocusableElement>) => void) | — | Not recommended – use onPress instead. onClick is an alias for onPress provided for compatibility with other libraries. onPress provides additional event details for non-mouse interactions. |
onPress | ((e: PressEvent) => void) | — | Handler that is called when the press is released over the target. |
onPressChange | ((isPressed: boolean) => void) | — | Handler that is called when the press state changes. |
onPressEnd | ((e: PressEvent) => void) | — | Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target. |
onPressStart | ((e: PressEvent) => void) | — | Handler that is called when a press interaction starts. |
onPressUp | ((e: PressEvent) => void) | — | Handler that is called when a press is released over the target, regardless of whether it started on the target or not. |
onHoverChange | ((isHovering: boolean) => void) | — | Handler that is called when the hover state changes. |
onHoverEnd | ((e: HoverEvent) => void) | — | Handler that is called when a hover interaction ends. |
onHoverStart | ((e: HoverEvent) => void) | — | Handler that is called when a hover interaction starts. |
onBlur | ((e: FocusEvent<Element, Element>) => void) | — | Handler that is called when the element loses focus. |
onFocus | ((e: FocusEvent<Element, Element>) => void) | — | Handler that is called when the element receives focus. |
onFocusChange | ((isFocused: boolean) => void) | — | Handler that is called when the element's focus status changes. |
download | string | boolean | — | Causes the browser to download the linked URL. A string may be provided to suggest a file name. |
href | string | — | A URL to link to. |
hrefLang | string | — | Hints at the human language of the linked URL. |
ping | string | — | A space-separated list of URLs to ping when the link is followed. |
referrerPolicy | """no-referrer""no-referrer-when-downgrade""origin""origin-when-cross-origin""same-origin""strict-origin""strict-origin-when-cross-origin""unsafe-url" | — | How much of the referrer to send when following the link. |
rel | string | — | The relationship between the linked resource and the current page. |
routerOptions | RouterOptions | — | Options for the configured client side router. |
target | HTMLAttributeAnchorTarget | — | The target window for the link. |
id | Key | — | The unique id of the item. |
isDisabled | boolean | — | Whether the item is disabled. |
onAction | (() => void) | — | Handler that is called when the item is selected. |
shouldCloseOnSelect | boolean | — | Whether the menu should close when the menu item is selected. |
textValue | string | — | A string representation of the item's contents, used for features like typeahead. |
value | object | — | The object value that this item represents. When using dynamic collections, this is set automatically. |
style | StyleOrFunction<MenuItemRenderProps> | — | The inline style for the element. A function may be provided to compute the style based on component state. |
children | ChildrenOrFunction<MenuItemRenderProps> | — | The children of the component. A function may be provided to alter the children based on component state. |
className | ClassNameOrFunction<MenuItemRenderProps> | — | The CSS className for the element. A function may be provided to compute the class based on component state. |
render | (props: DetailedHTMLProps<LinkWithRequiredHref, HTMLAnchorElement> | JSX.IntrinsicElements[Fallback], renderProps: T) => ReactElement | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Note: You can check if 'href' in props in order to tell whether to render an <a> element.Requirements:
|
aria-label | string | — | An accessibility label for this item. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
Dropdown.Menu
Renders React Aria’s Menu — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
autoFocus | falsetrue"first""last" | — | Where the focus should be set. |
children | ReactNode | ((item: T) => ReactNode) | — | The contents of the collection. |
defaultSelectedKeys | "all" | Iterable<Key> | — | The initial selected keys in the collection (uncontrolled). |
dependencies | readonly any[] | — | Values that should invalidate the item cache when using dynamic collections. |
disabledKeys | Iterable<Key> | — | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. |
disallowEmptySelection | boolean | — | Whether the collection allows empty selection. |
escapeKeyBehavior | "none""clearSelection" | "clearSelection" | Whether pressing the escape key should clear selection in the menu or not.Most experiences should not modify this option as it eliminates a keyboard user's ability to easily clear selection. Only use if the escape key is being handled externally or should not trigger selection clearing contextually. |
id | string | — | The element's unique identifier. |
items | Iterable<T> | — | Item objects in the collection. |
onAction | ((key: Key, value: T) => void) | — | Handler that is called when an item is selected. |
onClose | (() => void) | — | Handler that is called when the menu should close after selecting an item. |
onSelectionChange | ((keys: Selection) => void) | — | Handler that is called when the selection changes. |
renderEmptyState | (() => ReactNode) | — | Provides content to display when there are no items in the menu. |
selectedKeys | "all" | Iterable<Key> | — | The currently selected keys in the collection (controlled). |
selectionMode | "none""single""multiple" | — | The type of selection that is allowed in the collection. |
shouldCloseOnSelect | boolean | — | Whether the menu should close when the menu item is selected. |
shouldFocusWrap | boolean | — | Whether keyboard navigation is circular. |
Styling (4)
| Prop | Type | Default | Description |
|---|---|---|---|
style | StyleOrFunction<MenuRenderProps> | — | The inline style for the element. A function may be provided to compute the style based on component state. |
slot | string | null | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent. |
className | ClassNameOrFunction<MenuRenderProps> | — | The CSS className for the element. A function may be provided to compute the class based on component state. |
render | DOMRenderFunction<"div", MenuRenderProps> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
Accessibility (4)
| Prop | Type | Default | Description |
|---|---|---|---|
aria-describedby | string | — | Identifies the element (or elements) that describes the object. |
aria-details | string | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label | string | — | Defines a string value that labels the current element. |
aria-labelledby | string | — | Identifies the element (or elements) that labels the current element. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
Dropdown.Popover
Renders React Aria’s Popover — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
arrowBoundaryOffset | number | 0 | The minimum distance the arrow's edge should be from the edge of the overlay element. |
arrowRef | RefObject<Element | null> | — | A ref for the popover arrow element. |
boundaryElement | Element | document.body | Element that that serves as the positioning boundary. |
containerPadding | number | 12 | The placement padding that should be applied between the element and its surrounding container. |
crossOffset | number | 0 | The additional offset applied along the cross axis between the element and its anchor element. |
defaultOpen | boolean | — | Whether the overlay is open by default (uncontrolled). |
getTargetRect | ((target: Element) => DOMRect | null | undefined) | target.getBoundingClientRect() | Overrides the target element's bounding rectangle. Useful for positioning relative to a specific point such as the mouse cursor (e.g. context menus) or text selection. |
isEntering | boolean | — | Whether the popover is currently performing an entry animation. |
isExiting | boolean | — | Whether the popover is currently performing an exit animation. |
isKeyboardDismissDisabled | boolean | false | Whether pressing the escape key to close the popover should be disabled.Most popovers should not use this option. When set to true, an alternative way to close the popover with a keyboard must be provided. |
isNonModal | boolean | — | Whether the popover is non-modal, i.e. elements outside the popover may be interacted with by assistive technologies.Most popovers should not use this option as it may negatively impact the screen reader experience. Only use with components such as combobox, which are designed to handle this situation carefully. |
isOpen | boolean | — | Whether the overlay is open by default (controlled). |
maxHeight | number | — | The maxHeight specified for the overlay element. By default, it will take all space up to the current viewport height. |
offset | number | 8 | The additional offset applied along the main axis between the element and its anchor element. |
onBlurWithin | ((e: FocusEvent) => void) | — | Handler that is called when the target element and all descendants lose focus. |
onFocusWithin | ((e: FocusEvent) => void) | — | Handler that is called when the target element or a descendant receives focus. |
onFocusWithinChange | ((isFocusWithin: boolean) => void) | — | Handler that is called when the the focus within state changes. |
onOpenChange | ((isOpen: boolean) => void) | — | Handler that is called when the overlay's open state changes. |
placement | "bottom""bottom left""bottom right""bottom start""bottom end""top""top left""top right""top start""top end""left""left top""left bottom""start"+8 moreShow fewer"start top""start bottom""right""right top""right bottom""end""end top""end bottom" | "bottom right" | The placement of the element with respect to its anchor element. |
scrollRef | RefObject<Element | null> | overlayRef | A ref for the scrollable region within the overlay. |
shouldCloseOnInteractOutside | ((element: Element) => boolean) | — | When user interacts with the argument element outside of the popover ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the popover. By default, onClose will always be called on interaction outside the popover ref. |
shouldFlip | boolean | true | Whether the element should flip its orientation (e.g. top to bottom or left to right) when there is insufficient room for it to render completely. |
shouldSkipAnimation | boolean | — | Whether the popover should appear and disappear without an entry or exit animation. This is used by components such as PreviewTrigger to skip animations when quickly swapping between overlays. |
shouldUpdatePosition | boolean | true | Whether the overlay should update its position automatically. |
trigger | string | — | The name of the component that triggered the popover. This is reflected on the element as the data-trigger attribute, and can be used to provide specific styles for the popover depending on which element triggered it. |
triggerRef | RefObject<Element | null> | — | The ref for the element which the popover positions itself with respect to.When used within a trigger component such as DialogTrigger, MenuTrigger, Select, etc., this is set automatically. It is only required when used standalone. |
Styling (5)
| Prop | Type | Default | Description |
|---|---|---|---|
style | StyleOrFunction<PopoverRenderProps> | — | The inline style for the element. A function may be provided to compute the style based on component state. |
children | ChildrenOrFunction<PopoverRenderProps> | — | The children of the component. A function may be provided to alter the children based on component state. |
slot | string | null | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent. |
className | ClassNameOrFunction<PopoverRenderProps> | — | The CSS className for the element. A function may be provided to compute the class based on component state. |
render | DOMRenderFunction<"div", PopoverRenderProps> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
Accessibility (4)
| Prop | Type | Default | Description |
|---|---|---|---|
aria-describedby | string | — | Identifies the element (or elements) that describes the object. |
aria-details | string | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label | string | — | Defines a string value that labels the current element. |
aria-labelledby | string | — | Identifies the element (or elements) that labels the current element. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
Dropdown.Root
Renders React Aria’s MenuTrigger — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
children* (required) | ReactNode | — | — |
trigger | "press""longPress""contextMenu" | "press" | How the menu is triggered. |
isOpen | boolean | — | Whether the overlay is open by default (controlled). |
defaultOpen | boolean | — | Whether the overlay is open by default (uncontrolled). |
onOpenChange | ((isOpen: boolean) => void) | — | Handler that is called when the overlay's open state changes. |
Dropdown.Section
Renders React Aria’s MenuSection — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
shouldCloseOnSelect | boolean | — | Whether the menu should close when the menu item is selected. |
id | Key | — | The unique id of the section. |
value | T | — | The object value that this section represents. When using dynamic collections, this is set automatically. |
children | ReactNode | ((item: T) => ReactElement) | — | Static child items or a function to render children. |
dependencies | readonly any[] | — | Values that should invalidate the item cache when using dynamic collections. |
items | Iterable<T> | — | Item objects in the section. |
selectionMode | "none""single""multiple" | — | The type of selection that is allowed in the collection. |
disallowEmptySelection | boolean | — | Whether the collection allows empty selection. |
selectedKeys | "all" | Iterable<Key> | — | The currently selected keys in the collection (controlled). |
defaultSelectedKeys | "all" | Iterable<Key> | — | The initial selected keys in the collection (uncontrolled). |
onSelectionChange | ((keys: Selection) => void) | — | Handler that is called when the selection changes. |
Styling (3)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | The CSS className for the element. |
style | CSSProperties | — | The inline style for the element. |
render | DOMRenderFunction<"section", undefined> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
Accessibility (1)
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | — | An accessibility label for the section. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
Dropdown.SectionHeader
Renders React Aria’s Header — all of its props are supported.
Styling (1)
| Prop | Type | Default | Description |
|---|---|---|---|
render | DOMRenderFunction<"header", undefined> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
Also accepts all standard HTML attributes, all aria-* attributes, all standard React DOM event handlers.
Dropdown.Separator
Renders React Aria’s Separator — all of its props are supported.
| Prop | Type | Default | Description |
|---|---|---|---|
elementType | string | — | The HTML element type that will be used to render the separator. |
id | string | — | The element's unique identifier. |
orientation | "horizontal""vertical" | "horizontal" | The orientation of the separator. |
Styling (4)
| Prop | Type | Default | Description |
|---|---|---|---|
slot | string | null | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent. |
className | string | — | The CSS className for the element. |
render | DOMRenderFunction<"div" | "hr", undefined> | — | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
|
style | CSSProperties | — | The inline style for the element. |
Accessibility (4)
| Prop | Type | Default | Description |
|---|---|---|---|
aria-describedby | string | — | Identifies the element (or elements) that describes the object. |
aria-details | string | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label | string | — | Defines a string value that labels the current element. |
aria-labelledby | string | — | Identifies the element (or elements) that labels the current element. |
Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.
FAQs
Please refer to our frequently asked questions page for more.
Set the trigger prop to "contextMenu" on Dropdown.Root. The first child becomes the target area that opens the menu on right-click (or long-press on touch devices), and the menu opens at the pointer position instead of anchored to a button.
The target must be a React Aria pressable element, so wrap your content in an AriaButton (or Pressable) from react-aria-components. React Aria attaches the right-click and long-press handlers to it and manages focus and keyboard access for you.
With the target focused, press Shift+F10 on Windows and Linux or Control+Enter on macOS. Enter and Space do not open a context menu. Once it is open, the arrow keys move between items, Enter selects, and Escape closes the menu.
Yes. Wrap a Dropdown.Item and a nested Dropdown.Popover in a SubmenuTrigger from react-aria-components, exactly as you would in a regular dropdown. See the advanced example above for nested submenus.
Set selectionMode="multiple" (or "single") on a Dropdown.Section and control it with selectedKeys and onSelectionChange, as the advanced example does. Selected items show a checkmark by default; set selectionIndicator on Dropdown.Item to "checkbox", "radio", "toggle" or "none" to change it. Pass the addon prop on a Dropdown.Item to show a shortcut such as ⌘C.
Context menus reuse the Dropdown component, so install it with npx untitledui@latest add dropdown. The examples import Dropdown from @/components/base/dropdown/dropdown, plus Button (as AriaButton) and SubmenuTrigger from react-aria-components.