Context menu

Secondary actions kept close to the selected object.

pnpm dlx shadcn@latest add @uiarc/context-menu
Live · keyboard ready
  • Secondary actions on a file, card, or row where a visible menu button would add clutter.
  • Desktop-style right-click menus that also open from the keyboard with Shift+F10 or the ContextMenu key.
  • Short flat lists of item actions with one destructive option.
  • Use dropdown-menu when the actions deserve a visible trigger.
  • Use swipe-actions for touch-first lists like an inbox.
  • Avoid it on targets that need their own click action, since a plain click on the target also opens the menu.

Installation

Add Context menu with the shadcn CLI, or copy the source by hand.

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

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { ContextMenu } from "@/registry/components/context-menu/context-menu";import { Copy, Trash2 } from "lucide-react"; export function FileTile({ file }: { file: File }) {  return (    <ContextMenu      label={`Actions for ${file.name}`}      items={[        { id: "copy", label: "Copy link", icon: <Copy size={15} />, onSelect: () => copyLink(file) },        { id: "delete", label: "Delete file", icon: <Trash2 size={15} />, destructive: true, onSelect: () => remove(file) },      ]}    >      <FilePreview file={file} />    </ContextMenu>  );}

ContextMenu

Wraps content and opens a menu at the pointer on right-click, or under the target on click and keyboard.

PropTypeDefaultDescription
childrenRequiredReactNode–The target area.
itemsRequiredContextMenuItem[]–Items: { id, label, icon?, onSelect?, disabled?, destructive?, checked? }.
labelstring"Context menu"Accessible name for both the target and the menu.
ContextMenuorShift+F10
Opens the menu under the focused target.
ArrowDownorArrowUp
Moves between enabled items, wrapping at the ends.
HomeorEnd
Jumps to the first or last enabled item.
EnterorSpace
Selects the focused item and closes the menu.
Escape
Closes the menu and returns focus to the target.
  • The target is focusable with aria-haspopup="menu" and aria-expanded; the menu has role="menu" and items role="menuitem".
  • Opening focuses the first enabled item; closing returns focus to the target.
  • Items without an icon show a check when checked, but checked state is not exposed to assistive tech, so say it in the label if it matters.
  • The menu grows from the pointer on a snappy spring, even when clamped away from a viewport edge; reopening fades the old one out in place.
  • A shared highlight glides between rows for the pointer and jumps for the keyboard.
  • Reduced motion drops the scale and glide and uses a short opacity fade.
  • The menu is clamped 8px inside the viewport and capped at the viewport width minus 16px, with a max height of 300px and scrolling beyond that.
  • On touch, a tap on the target opens the menu under it, so it works without a right mouse button.
  • The menu closes on any scroll or resize instead of repositioning.
  • The menu mounts only while open and is positioned once from the pointer, with no scroll tracking loop.
  • Items are plain buttons with one shared highlight element; there is no virtualization, so keep the list short.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use for secondary actions on a content object (file, card, row) where a visible menu button would add clutter. Use dropdown-menu when the commands deserve a visible trigger.
  • A plain click on the target also opens the menu, so do not wrap targets that need their own click action.
  • The menu closes on scroll, resize, and outside press; keep items to a short flat list.

The full library index for assistants is at /llms.txt.