Skip to content

Context menu

Opens a menu of actions on right-click, like on a file tile or a list row.

Library
What’s this?
Right click here

Installation

pnpm dlx shadcn@latest add @wisty/context-menu

The CLI installs the Radix or Base UI file to match your project.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • People right-click an object to act on it, like a file tile, a list row or a card.
  • As a shortcut to actions that also live somewhere visible.
  • In a canvas or editor where a right-click on an element is the usual way in, like a page builder.

Don't use it

  • The menu would be the only way to reach an action. Many people never right-click, and touch screens need a long press. Show a button or a Dropdown menu as well.
  • A button opens the menu. Use Dropdown menu.
  • People pick a value for a form field. Use Select.
  • A bar of menus along the top of an app, like File and Edit. Use Menubar.

Usage

ContextMenu
├── ContextMenuTrigger
└── ContextMenuContent
    ├── ContextMenuGroup
    │   ├── ContextMenuLabel
    │   └── ContextMenuItem
    │       └── ContextMenuShortcut
    ├── ContextMenuSeparator
    └── ContextMenuSub
        ├── ContextMenuSubTrigger
        └── ContextMenuSubContent
            └── ContextMenuItem

The trigger is the area people right-click. It has no style of its own, so give it a display, a size and a focus style.

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"
<ContextMenu>
  <ContextMenuTrigger
    tabIndex={0}
    className="flex rounded-(--radius-2) border border-border p-4 outline-none focus-visible:shadow-(--shadow-focus)"
  >
    Acme Corp
  </ContextMenuTrigger>
  <ContextMenuContent>
    <ContextMenuItem onClick={editAccount}>Edit</ContextMenuItem>
  </ContextMenuContent>
</ContextMenu>
  • Run an action with onClick, which works in Radix and Base UI projects; onSelect is Radix only.
  • For choices, use ContextMenuCheckboxItem, or ContextMenuRadioItem inside a ContextMenuRadioGroup, in an item's place. inset on an item, label or submenu trigger indents its text to line up with theirs.
  • In Radix projects, checking a checkbox or radio item closes the menu; call event.preventDefault() in its onSelect to keep it open. In Base UI projects the menu stays open; pass closeOnClick to close it.
  • The menu opens at the pointer, to its right. In Radix projects it always does: ContextMenuContent ignores side, sideOffset and align, so leave them off. In Base UI projects they move it.

Examples

Checkbox and radio items

Checkbox items (`ContextMenuCheckboxItem`) for what to show, radio items for the sort order, and an item lined up with them by `inset`.

OpportunitiesRight-click or press the Menu key for view options

API reference

SLDS mapping

SLDS has no context menu. This is SLDS's menu, opened at the pointer.

  • ContextMenuContent and ContextMenuSubContent are slds-dropdown.
  • ContextMenuItem, ContextMenuCheckboxItem and ContextMenuRadioItem are slds-dropdown__item. Checked items show SLDS's selected check (slds-icon_selected) before the text.
  • ContextMenuLabel is slds-dropdown__header.
  • ContextMenuSeparator is slds-has-divider_top-space.
  • ContextMenuSubTrigger is an item with slds-has-submenu.
  • ContextMenuShortcut and ContextMenuTrigger have no SLDS counterpart. The examples draw the trigger as SLDS's file selector drop zone (slds-file-selector__dropzone).

Known gaps:

  • No nubbin, and no slds-dropdown_length-* heights. The menu scrolls only when it runs out of room on screen.
  • Icons are lucide's, not SLDS's utility icons.
  • SLDS truncates a long item on one line. Here it wraps, unless you wrap the label in <span className="truncate">.
  • A submenu trigger keeps its highlight while its submenu is open. SLDS drops it once focus moves into the submenu.
PropValueSLDSNotes
ContextMenuItem variantdefaultslds-dropdown__item
ContextMenuItem variantdestructivenoneSLDS has no destructive item. The text and icon take the error color; the highlight stays.
ContextMenuItem insettruenoneStarts the text where a checked item's text starts.

Keyboard interactions

Keys Action
Menu or Shift+F10 On the focused trigger, opens the menu.
Down Arrow, Up Arrow Moves focus to the next or previous item.
Home, End Moves focus to the first or last item.
Letters Moves focus to the next item that starts with them.
Enter or Space Runs the focused item, or checks it.
Right Arrow On a submenu trigger, opens the submenu and focuses its first item.
Left Arrow In a submenu, closes it and returns focus to its trigger.
Escape Closes the menu.

Opened from the keyboard, in Radix projects the first item takes focus, and the arrow keys stop at the first and last items. In Base UI projects the menu takes focus with no item highlighted, the first Down Arrow reaches the first item, and the arrow keys wrap. In Radix projects the arrow keys skip disabled items. In Base UI projects focus lands on them, but Enter and Space don't run them.

Macs have no Menu key, and browsers differ on Shift+F10, so keyboard users may have no way in. Keep the actions reachable elsewhere.

Accessibility

  • The trigger has no role and isn't in the tab order. Give it tabIndex={0} and text that says what it holds.
  • The menu is modal. While it's open, the page doesn't scroll, a click outside only closes it, and the rest of the page is hidden from screen readers or kept out of the focus order.
  • A disabled item still reads out. Say why it's unavailable in nearby text if it matters.
  • In Base UI projects a ContextMenuLabel names its ContextMenuGroup for screen readers. In Radix projects it's only text, so give the group an aria-label when its name matters.

Performance

  • Use one ContextMenu per area. For a long list, put one around the list and read which row was clicked, rather than one per row.

Rules

  • Use a context menu only as a shortcut. Put the same actions in a visible Dropdown menu or buttons too.
  • Put each ContextMenuLabel inside a ContextMenuGroup, or the menu can throw.
  • Put an icon first in an item, then the text, then an optional ContextMenuShortcut. The shortcut only shows the keys; it doesn't make them work.
  • Use variant="destructive" only for actions that delete or can't be undone, and put them last, after a separator.
  • Don't restyle highlight, focus or check colors. They come from the theme tokens.