Components

Context Menu

Displays a menu of actions triggered by a right click.

Right click here

Installation

Cortexcn
pnpm dlx shadcn@latest add @cortexcn/context-menu

Usage

import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuPortal, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup } from "@/components/context-menu";

Examples

Basic

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuBasic() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuItem>Back</ContextMenuItem>            <ContextMenuItem disabled>Forward</ContextMenuItem>            <ContextMenuItem>Reload</ContextMenuItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With sides

Right click (top)Right click (right)Right click (bottom)Right click (left)
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithSides() {  return (    <div className="flex flex-col gap-6">      <div className="grid grid-cols-2 gap-6">        <ContextMenu>          <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">            Right click (top)          </ContextMenuTrigger>          <ContextMenuContent side="top">            <ContextMenuGroup>              <ContextMenuItem>Back</ContextMenuItem>              <ContextMenuItem>Forward</ContextMenuItem>              <ContextMenuItem>Reload</ContextMenuItem>            </ContextMenuGroup>          </ContextMenuContent>        </ContextMenu>        <ContextMenu>          <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">            Right click (right)          </ContextMenuTrigger>          <ContextMenuContent side="right">            <ContextMenuGroup>              <ContextMenuItem>Back</ContextMenuItem>              <ContextMenuItem>Forward</ContextMenuItem>              <ContextMenuItem>Reload</ContextMenuItem>            </ContextMenuGroup>          </ContextMenuContent>        </ContextMenu>        <ContextMenu>          <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">            Right click (bottom)          </ContextMenuTrigger>          <ContextMenuContent side="bottom">            <ContextMenuGroup>              <ContextMenuItem>Back</ContextMenuItem>              <ContextMenuItem>Forward</ContextMenuItem>              <ContextMenuItem>Reload</ContextMenuItem>            </ContextMenuGroup>          </ContextMenuContent>        </ContextMenu>        <ContextMenu>          <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">            Right click (left)          </ContextMenuTrigger>          <ContextMenuContent side="left">            <ContextMenuGroup>              <ContextMenuItem>Back</ContextMenuItem>              <ContextMenuItem>Forward</ContextMenuItem>              <ContextMenuItem>Reload</ContextMenuItem>            </ContextMenuGroup>          </ContextMenuContent>        </ContextMenu>      </div>    </div>  )}

With icons

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger } from "@/components/context-menu"import { ClipboardPasteIcon, CopyIcon, ScissorsIcon, TrashIcon } from "lucide-react"export function ContextMenuWithIcons() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuItem>              <CopyIcon />              Copy            </ContextMenuItem>            <ContextMenuItem>              <ScissorsIcon />              Cut            </ContextMenuItem>            <ContextMenuItem>              <ClipboardPasteIcon />              Paste            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuItem variant="destructive">              <TrashIcon />              Delete            </ContextMenuItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With shortcuts

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithShortcuts() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuItem>              Back              <ContextMenuShortcut>⌘[</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem disabled>              Forward              <ContextMenuShortcut>⌘]</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Reload              <ContextMenuShortcut>⌘R</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuItem>              Save              <ContextMenuShortcut>⌘S</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Save As...              <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With submenu

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithSubmenu() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuItem>              Copy              <ContextMenuShortcut>⌘C</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Cut              <ContextMenuShortcut>⌘X</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSub>            <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>            <ContextMenuSubContent>              <ContextMenuGroup>                <ContextMenuItem>Save Page...</ContextMenuItem>                <ContextMenuItem>Create Shortcut...</ContextMenuItem>                <ContextMenuItem>Name Window...</ContextMenuItem>              </ContextMenuGroup>              <ContextMenuSeparator />              <ContextMenuGroup>                <ContextMenuItem>Developer Tools</ContextMenuItem>              </ContextMenuGroup>              <ContextMenuSeparator />              <ContextMenuGroup>                <ContextMenuItem variant="destructive">Delete</ContextMenuItem>              </ContextMenuGroup>            </ContextMenuSubContent>          </ContextMenuSub>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With groups, labels and separators

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithGroups() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuLabel>File</ContextMenuLabel>            <ContextMenuItem>              New File              <ContextMenuShortcut>⌘N</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Open File              <ContextMenuShortcut>⌘O</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Save              <ContextMenuShortcut>⌘S</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuLabel>Edit</ContextMenuLabel>            <ContextMenuItem>              Undo              <ContextMenuShortcut>⌘Z</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Redo              <ContextMenuShortcut>⇧⌘Z</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuSeparator />            <ContextMenuItem>              Cut              <ContextMenuShortcut>⌘X</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Copy              <ContextMenuShortcut>⌘C</ContextMenuShortcut>            </ContextMenuItem>            <ContextMenuItem>              Paste              <ContextMenuShortcut>⌘V</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuItem variant="destructive">              Delete              <ContextMenuShortcut>⌫</ContextMenuShortcut>            </ContextMenuItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With checkboxes

Right click here
import * as React from "react"import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithCheckboxes() {  const [showBookmarksBar, setShowBookmarksBar] = React.useState(true)  const [showFullUrls, setShowFullUrls] = React.useState(false)  const [showDeveloperTools, setShowDeveloperTools] = React.useState(false)  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuCheckboxItem              checked={showBookmarksBar}              onCheckedChange={setShowBookmarksBar}            >              Show Bookmarks Bar            </ContextMenuCheckboxItem>            <ContextMenuCheckboxItem              checked={showFullUrls}              onCheckedChange={setShowFullUrls}            >              Show Full URLs            </ContextMenuCheckboxItem>            <ContextMenuCheckboxItem              checked={showDeveloperTools}              onCheckedChange={setShowDeveloperTools}            >              Show Developer Tools            </ContextMenuCheckboxItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With radio group

Right click here
import * as React from "react"import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuTrigger } from "@/components/context-menu"export function ContextMenuWithRadio() {  const [user, setUser] = React.useState("pedro")  const [theme, setTheme] = React.useState("light")  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuLabel>People</ContextMenuLabel>            <ContextMenuRadioGroup value={user} onValueChange={setUser}>              <ContextMenuRadioItem value="pedro">                Pedro Duarte              </ContextMenuRadioItem>              <ContextMenuRadioItem value="colm">                Colm Tuite              </ContextMenuRadioItem>            </ContextMenuRadioGroup>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuLabel>Theme</ContextMenuLabel>            <ContextMenuRadioGroup value={theme} onValueChange={setTheme}>              <ContextMenuRadioItem value="light">Light</ContextMenuRadioItem>              <ContextMenuRadioItem value="dark">Dark</ContextMenuRadioItem>              <ContextMenuRadioItem value="system">System</ContextMenuRadioItem>            </ContextMenuRadioGroup>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

With destructive items

Right click here
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger } from "@/components/context-menu"import { ArchiveIcon, PencilIcon, ShareIcon, TrashIcon } from "lucide-react"export function ContextMenuWithDestructive() {  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent>          <ContextMenuGroup>            <ContextMenuItem>              <PencilIcon />              Edit            </ContextMenuItem>            <ContextMenuItem>              <ShareIcon />              Share            </ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuItem>              <ArchiveIcon />              Archive            </ContextMenuItem>            <ContextMenuItem variant="destructive">              <TrashIcon />              Delete            </ContextMenuItem>          </ContextMenuGroup>        </ContextMenuContent>      </ContextMenu>    </div>  )}

In dialog

import { Button } from "@/components/button"import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/context-menu"import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/dialog"import { ClipboardPasteIcon, CopyIcon, ScissorsIcon, TrashIcon } from "lucide-react"export function ContextMenuInDialog() {  return (    <div className="flex flex-col gap-6">      <Dialog>        <DialogTrigger asChild>          <Button variant="outline">Open Dialog</Button>        </DialogTrigger>        <DialogContent>          <DialogHeader>            <DialogTitle>Context Menu Example</DialogTitle>            <DialogDescription>              Right click on the area below to see the context menu.            </DialogDescription>          </DialogHeader>          <ContextMenu>            <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">              Right click here            </ContextMenuTrigger>            <ContextMenuContent>              <ContextMenuGroup>                <ContextMenuItem>                  <CopyIcon />                  Copy                </ContextMenuItem>                <ContextMenuItem>                  <ScissorsIcon />                  Cut                </ContextMenuItem>                <ContextMenuItem>                  <ClipboardPasteIcon />                  Paste                </ContextMenuItem>              </ContextMenuGroup>              <ContextMenuSeparator />              <ContextMenuSub>                <ContextMenuSubTrigger>More Options</ContextMenuSubTrigger>                <ContextMenuSubContent>                  <ContextMenuGroup>                    <ContextMenuItem>Save Page...</ContextMenuItem>                    <ContextMenuItem>Create Shortcut...</ContextMenuItem>                    <ContextMenuItem>Name Window...</ContextMenuItem>                  </ContextMenuGroup>                  <ContextMenuSeparator />                  <ContextMenuGroup>                    <ContextMenuItem>Developer Tools</ContextMenuItem>                  </ContextMenuGroup>                </ContextMenuSubContent>              </ContextMenuSub>              <ContextMenuSeparator />              <ContextMenuGroup>                <ContextMenuItem variant="destructive">                  <TrashIcon />                  Delete                </ContextMenuItem>              </ContextMenuGroup>            </ContextMenuContent>          </ContextMenu>        </DialogContent>      </Dialog>    </div>  )}

With inset

Right click here
import * as React from "react"import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/context-menu"import { CopyIcon, ScissorsIcon } from "lucide-react"export function ContextMenuWithInset() {  const [showBookmarks, setShowBookmarks] = React.useState(true)  const [showUrls, setShowUrls] = React.useState(false)  const [theme, setTheme] = React.useState("system")  return (    <div className="flex flex-col gap-6">      <ContextMenu>        <ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">          Right click here        </ContextMenuTrigger>        <ContextMenuContent className="w-44">          <ContextMenuGroup>            <ContextMenuLabel>Actions</ContextMenuLabel>            <ContextMenuItem>              <CopyIcon />              Copy            </ContextMenuItem>            <ContextMenuItem>              <ScissorsIcon />              Cut            </ContextMenuItem>            <ContextMenuItem inset>Paste</ContextMenuItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuLabel inset>Appearance</ContextMenuLabel>            <ContextMenuCheckboxItem              inset              checked={showBookmarks}              onCheckedChange={setShowBookmarks}            >              Bookmarks            </ContextMenuCheckboxItem>            <ContextMenuCheckboxItem              inset              checked={showUrls}              onCheckedChange={setShowUrls}            >              Full URLs            </ContextMenuCheckboxItem>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuGroup>            <ContextMenuLabel inset>Theme</ContextMenuLabel>            <ContextMenuRadioGroup value={theme} onValueChange={setTheme}>              <ContextMenuRadioItem inset value="light">                Light              </ContextMenuRadioItem>              <ContextMenuRadioItem inset value="dark">                Dark              </ContextMenuRadioItem>              <ContextMenuRadioItem inset value="system">                System              </ContextMenuRadioItem>            </ContextMenuRadioGroup>          </ContextMenuGroup>          <ContextMenuSeparator />          <ContextMenuSub>            <ContextMenuSubTrigger inset>More Options</ContextMenuSubTrigger>            <ContextMenuSubContent>              <ContextMenuGroup>                <ContextMenuItem>Save Page...</ContextMenuItem>                <ContextMenuItem>Create Shortcut...</ContextMenuItem>              </ContextMenuGroup>            </ContextMenuSubContent>          </ContextMenuSub>        </ContextMenuContent>      </ContextMenu>    </div>  )}

Adapted from the shadcn/ui Context Menu (MIT).