Context menu

Secondary actions kept close to the selected object.

menuaction
Preview
Context menu preview

When to use

  • 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.

When not to use

  • 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.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "type": "registry:ui",
  "title": "Context menu",
  "description": "Secondary actions kept close to the selected object.",
  "categories": [
    "actions"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/context-menu/context-menu.tsx",
      "type": "registry:component",
      "target": "@components/manicat/context-menu/context-menu.tsx"
    },
    {
      "path": "registry/components/context-menu/context-menu.module.css",
      "type": "registry:component",
      "target": "@components/manicat/context-menu/context-menu.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/context-menu",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/context-menu",
    "markdown": "https://uiarc.dev/components/context-menu/markdown",
    "tags": [
      "menu",
      "action"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { ContextMenu, contextMenuExampleItems } from "@/components/manicat/context-menu/context-menu";

export function ContextMenuExample() {
  return (
    <ContextMenu items={contextMenuExampleItems} label="File actions">
      <div className="flex w-full flex-col gap-2 rounded-xl border border-(color:--border) p-4 text-sm">
        <span className="font-medium">report-q3.pdf</span>
        <span className="text-(color:--text-muted)">Right click, or press the menu key.</span>
      </div>
    </ContextMenu>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

File context menu Right-click (or press the menu key) anywhere on the card.

File context menu Right-click (or press the menu key) anywhere on the card. preview

Keyboard interactions

KeysAction
ContextMenu / Shift+F10Opens the menu under the focused target.
ArrowDown / ArrowUpMoves between enabled items, wrapping at the ends.
Home / EndJumps to the first or last enabled item.
Enter / SpaceSelects the focused item and closes the menu.
EscapeCloses the menu and returns focus to the target.

Accessibility

  • 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.

Motion

  • 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.

Responsive behavior

  • 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.

Performance

  • 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

  • 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.