Context Menu

Right-click menu for contextual actions and shortcuts.

Installation

npx shadcn@latest add @iconiq/b-context-menu

File Structure

Usage

"use client";

import { useState } from "react";
import { Copy, PencilLine, Share2, Trash2 } from "lucide-react";
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuGroup,
  ContextMenuItem,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuCheckboxItem,
  ContextMenuLabel,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuTrigger,
  contextMenuTriggerClassName,
} from "@/components/ui/b-context-menu";

export function ContextMenuPreview() {
  const [open, setOpen] = useState(false);
  const [person, setPerson] = useState("pedro");
  return (
    <ContextMenu>
      <ContextMenuTrigger asChild className="w-full max-w-xl">
        <div className={contextMenuTriggerClassName + " w-full border border-border/80 px-6 py-14 text-center"}>
          <p className="font-medium text-[15px] tracking-[-0.02em]">Right-click this block</p>
        </div>
      </ContextMenuTrigger>
      <ContextMenuContent className="w-52" collisionPadding={8}>
        <ContextMenuGroup>
          <ContextMenuItem>
            <PencilLine className="size-3.5 opacity-70" />
            Rename
            <ContextMenuShortcut>R</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuItem>
            <Copy className="size-3.5 opacity-70" />
            Duplicate
          </ContextMenuItem>
          <ContextMenuItem>
            <Share2 className="size-3.5 opacity-70" />
            Share
          </ContextMenuItem>
          <ContextMenuSub>
            <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
            <ContextMenuSubContent className="w-44">
              <ContextMenuItem>Save Page...</ContextMenuItem>
              <ContextMenuItem>Create Shortcut...</ContextMenuItem>
            </ContextMenuSubContent>
          </ContextMenuSub>
          <ContextMenuSeparator />
          <ContextMenuItem variant="destructive">
            <Trash2 className="size-3.5 opacity-70" />
            Delete
            <ContextMenuShortcut>Del</ContextMenuShortcut>
          </ContextMenuItem>
        </ContextMenuGroup>
        <ContextMenuSeparator />
        <ContextMenuGroup>
          <ContextMenuCheckboxItem checked>Show Shortcuts</ContextMenuCheckboxItem>
          <ContextMenuCheckboxItem disabled>Show Metadata</ContextMenuCheckboxItem>
        </ContextMenuGroup>
        <ContextMenuSeparator />
        <ContextMenuGroup>
          <ContextMenuRadioGroup value={person} onValueChange={setPerson}>
            <ContextMenuLabel>People</ContextMenuLabel>
            <ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem>
            <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
          </ContextMenuRadioGroup>
        </ContextMenuGroup>
      </ContextMenuContent>
    </ContextMenu>
  );
}

Props

Props
Description

ContextMenu

children

Compose ContextMenuTrigger, ContextMenuContent, and item primitives such as ContextMenuItem or ContextMenuSub inside the root.

Type ReactNode

open

Controlled open state for the menu surface.

Type boolean

defaultOpen

Initial open state for uncontrolled usage.

Type boolean·Default false

onOpenChange

Called whenever the trigger, outside interaction, or Escape key changes the open state.

Type (open: boolean) => void

ContextMenuTrigger

children

Trigger content rendered inside the context-click target.

Type ReactNode

asChild

Merges trigger behavior onto the single child element instead of rendering a wrapper element.

Type boolean

className

Merged onto the trigger surface, including the focus ring and theme token scope.

Type string

ContextMenuContent

children

Menu body content such as groups, items, separators, checkbox rows, and nested submenus.

Type ReactNode

className

Merged onto the animated panel shell. Use width utilities such as w-48 when you want a fixed menu width.

Type string

collisionPadding

Viewport padding used while the underlying primitive resolves collision-aware placement.

Type number·Default 8

ContextMenuItem

children

Row content. Pair with ContextMenuShortcut when you want trailing keyboard hints.

Type ReactNode

variant

Switches the row into the destructive color treatment used for irreversible actions.

Type "default" | "destructive"·Default default

disabled

Dims the row and blocks pointer and keyboard selection.

Type boolean

inset

Adds extra start padding so the row aligns with checkbox and radio items.

Type boolean

onSelect

Called when the row is activated.

Type (event: Event) => void

ContextMenuShortcut

children

Shortcut copy such as ⌘R or Del.

Type ReactNode

className

Merged onto the trailing shortcut span.

Type string

ContextMenuSub

children

Submenu trigger and content parts rendered inside the parent menu.

Type ReactNode

ContextMenuCheckboxItem

checked

Controls whether the row renders in the checked state.

Type boolean

onCheckedChange

Called when the row toggles between checked and unchecked.

Type (checked: boolean) => void

disabled

Dims the row and blocks pointer and keyboard selection.

Type boolean

inset

Adds extra start padding to align with sibling rows.

Type boolean

ContextMenuRadioGroup

value

Controlled selected value for the radio group.

Type string

onValueChange

Called when a radio row is selected.

Type (value: string) => void

Registry bundle

Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.

Dependencies: @base-ui/react, motion, lucide-react.

Installs the Base UI context-menu parts under the composable ContextMenu API.

The generated registry file is /r/b-context-menu.json.

Contact

Additionally, if you find any bug or issue, feel free to raise an issue.

Right-click this workspace block

Shift+F10 and the Context Menu key also open the menu from keyboard focus.