or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-radix-ui--react-context-menu

React context menu primitive component with right-click and long-press support built on accessible menu foundations

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@radix-ui/react-context-menu@2.2.x

To install, run

npx @tessl/cli install tessl/npm-radix-ui--react-context-menu@2.2.0

index.mddocs/

Radix UI React Context Menu

A React context menu primitive component that provides accessible context menus with right-click and long-press support, built on top of Radix UI's menu foundation. Offers complete keyboard navigation, focus management, and customizable styling.

Package Information

  • Package Name: @radix-ui/react-context-menu
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @radix-ui/react-context-menu

Core Imports

import * as ContextMenu from "@radix-ui/react-context-menu";

Or import specific components:

import { 
  ContextMenu, 
  ContextMenuTrigger, 
  ContextMenuContent,
  ContextMenuItem 
} from "@radix-ui/react-context-menu";

For CommonJS:

const ContextMenu = require("@radix-ui/react-context-menu");

Basic Usage

import * as ContextMenu from "@radix-ui/react-context-menu";

function App() {
  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger className="trigger">
        Right click me
      </ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content className="context-menu">
          <ContextMenu.Item>
            Cut
          </ContextMenu.Item>
          <ContextMenu.Item>
            Copy
          </ContextMenu.Item>
          <ContextMenu.Item>
            Paste
          </ContextMenu.Item>
          <ContextMenu.Separator />
          <ContextMenu.Item>
            Delete
          </ContextMenu.Item>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  );
}

Architecture

The context menu system is built around several key architectural components:

Foundation Architecture:

  • Menu Primitive Foundation: Built on @radix-ui/react-menu, inheriting full accessibility and keyboard navigation
  • Primitive Component System: Components extend @radix-ui/react-primitive for composition with asChild prop support
  • Scoped Context System: Uses createContextScope for isolated context management and safe composition with other Radix components
  • Popper Positioning: Integrates @radix-ui/react-popper for collision detection and smart positioning

Interaction Model:

  • Context Management: React context manages open/closed state across component tree
  • Trigger System: Handles right-click (desktop) and long-press (touch) interactions with 700ms timer
  • Virtual Anchor: Uses virtual reference for positioning menu at mouse cursor location
  • Portal Rendering: Renders content outside DOM tree to avoid z-index and overflow issues
  • Focus Management: Automatic focus trapping, restoration, and roving tabindex for accessibility

Component Inheritance:

  • Most components extend their @radix-ui/react-menu counterparts and inherit all props
  • ContextMenuContent omits positioning props (side, sideOffset, align) that are automatically managed
  • All components support primitive composition via asChild prop where applicable

Capabilities

Root Component

The main context menu container that manages state and provides context to child components.

/**
 * Root context menu component
 */
interface ContextMenuProps {
  children?: React.ReactNode;
  onOpenChange?(open: boolean): void;
  dir?: Direction;
  modal?: boolean; // default: true
}

const ContextMenu: React.FC<ContextMenuProps>;

// Short name alias
const Root: typeof ContextMenu;

type Direction = "ltr" | "rtl";

Trigger Component

Element that triggers the context menu on right-click or long-press.

/**
 * Context menu trigger element
 */
interface ContextMenuTriggerProps extends React.ComponentPropsWithoutRef<typeof Primitive.span> {
  disabled?: boolean;
}

// Note: Primitive.span extends standard HTML span element with asChild support

const ContextMenuTrigger: React.ForwardRefExoticComponent<
  ContextMenuTriggerProps & React.RefAttributes<HTMLSpanElement>
>;

// Short name alias
const Trigger: typeof ContextMenuTrigger;

Portal Component

Portal component for rendering menu content outside the DOM tree.

/**
 * Portal for context menu content
 */
interface ContextMenuPortalProps {
  children?: React.ReactNode;
  container?: HTMLElement | null;
}

const ContextMenuPortal: React.FC<ContextMenuPortalProps>;

// Short name alias
const Portal: typeof ContextMenuPortal;

Content Component

Main container for menu items with positioning and focus management.

/**
 * Context menu content container
 * Extends MenuPrimitive.Content but omits positioning props that are automatically managed
 */
interface ContextMenuContentProps extends Omit<
  React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content>,
  "onEntryFocus" | "side" | "sideOffset" | "align"
> {
  onEscapeKeyDown?(event: KeyboardEvent): void;
  onPointerDownOutside?(event: PointerDownOutsideEvent): void;
  onFocusOutside?(event: FocusOutsideEvent): void;
  onInteractOutside?(event: InteractOutsideEvent): void;
  forceMount?: true;
  loop?: boolean;
  onCloseAutoFocus?(event: Event): void;
  disableOutsidePointerEvents?: boolean;
  disableOutsideScroll?: boolean;
  trapFocus?: boolean;
  // Inherited positioning props (automatically managed)
  // side: 'right' (fixed)
  // sideOffset: 2 (fixed)
  // align: 'start' (fixed)
  // Collision detection
  avoidCollisions?: boolean;
  collisionBoundary?: Element | null | Array<Element | null>;
  collisionPadding?: number | Partial<Record<Side, number>>;
  // Advanced positioning
  arrowPadding?: number;
  sticky?: "partial" | "always";
  hideWhenDetached?: boolean;
  updatePositionStrategy?: "optimized" | "always";
}

const ContextMenuContent: React.ForwardRefExoticComponent<
  ContextMenuContentProps & React.RefAttributes<HTMLDivElement>
>;

// Short name alias
const Content: typeof ContextMenuContent;

Menu Structure Components

Components for organizing menu items and providing visual structure.

/**
 * Groups related menu items together
 */
interface ContextMenuGroupProps extends React.ComponentPropsWithoutRef<"div"> {}

const ContextMenuGroup: React.ForwardRefExoticComponent<
  ContextMenuGroupProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Accessible label for menu groups
 */
interface ContextMenuLabelProps extends React.ComponentPropsWithoutRef<"div"> {}

const ContextMenuLabel: React.ForwardRefExoticComponent<
  ContextMenuLabelProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Visual separator between menu items
 */
interface ContextMenuSeparatorProps extends React.ComponentPropsWithoutRef<"div"> {}

const ContextMenuSeparator: React.ForwardRefExoticComponent<
  ContextMenuSeparatorProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Arrow pointing from menu to trigger
 */
interface ContextMenuArrowProps extends React.ComponentPropsWithoutRef<"svg"> {
  width?: number;
  height?: number;
}

const ContextMenuArrow: React.ForwardRefExoticComponent<
  ContextMenuArrowProps & React.RefAttributes<SVGSVGElement>
>;

// Short name aliases
const Group: typeof ContextMenuGroup;
const Label: typeof ContextMenuLabel;
const Separator: typeof ContextMenuSeparator;
const Arrow: typeof ContextMenuArrow;

Menu Item Components

Interactive components for menu actions and selections.

/**
 * Basic interactive menu item
 */
interface ContextMenuItemProps extends React.ComponentPropsWithoutRef<"div"> {
  disabled?: boolean;
  onSelect?(event: Event): void;
  textValue?: string;
}

const ContextMenuItem: React.ForwardRefExoticComponent<
  ContextMenuItemProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Menu item with checkbox functionality
 */
interface ContextMenuCheckboxItemProps extends React.ComponentPropsWithoutRef<"div"> {
  checked?: boolean | "indeterminate";
  onCheckedChange?(checked: boolean): void;
  disabled?: boolean;
  onSelect?(event: Event): void;
  textValue?: string;
}

const ContextMenuCheckboxItem: React.ForwardRefExoticComponent<
  ContextMenuCheckboxItemProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Container for radio menu items
 */
interface ContextMenuRadioGroupProps extends React.ComponentPropsWithoutRef<"div"> {
  value?: string;
  onValueChange?(value: string): void;
}

const ContextMenuRadioGroup: React.ForwardRefExoticComponent<
  ContextMenuRadioGroupProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Menu item with radio button functionality
 */
interface ContextMenuRadioItemProps extends React.ComponentPropsWithoutRef<"div"> {
  value: string;
  disabled?: boolean;
  onSelect?(event: Event): void;
  textValue?: string;
}

const ContextMenuRadioItem: React.ForwardRefExoticComponent<
  ContextMenuRadioItemProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Visual indicator for checked/selected states
 */
interface ContextMenuItemIndicatorProps extends React.ComponentPropsWithoutRef<"span"> {
  forceMount?: true;
}

const ContextMenuItemIndicator: React.ForwardRefExoticComponent<
  ContextMenuItemIndicatorProps & React.RefAttributes<HTMLSpanElement>
>;

// Short name aliases
const Item: typeof ContextMenuItem;
const CheckboxItem: typeof ContextMenuCheckboxItem;
const RadioGroup: typeof ContextMenuRadioGroup;
const RadioItem: typeof ContextMenuRadioItem;
const ItemIndicator: typeof ContextMenuItemIndicator;

Submenu Components

Components for creating nested menu structures.

/**
 * Container for submenu functionality
 */
interface ContextMenuSubProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?(open: boolean): void;
}

const ContextMenuSub: React.FC<ContextMenuSubProps>;

/**
 * Menu item that triggers a submenu
 */
interface ContextMenuSubTriggerProps extends React.ComponentPropsWithoutRef<"div"> {
  disabled?: boolean;
  textValue?: string;
}

const ContextMenuSubTrigger: React.ForwardRefExoticComponent<
  ContextMenuSubTriggerProps & React.RefAttributes<HTMLDivElement>
>;

/**
 * Container for submenu items
 */
interface ContextMenuSubContentProps extends React.ComponentPropsWithoutRef<"div"> {
  onEscapeKeyDown?(event: KeyboardEvent): void;
  onPointerDownOutside?(event: PointerDownOutsideEvent): void;
  onFocusOutside?(event: FocusOutsideEvent): void;
  onInteractOutside?(event: InteractOutsideEvent): void;
  forceMount?: true;
  loop?: boolean;
  sideOffset?: number;
  alignOffset?: number;
  avoidCollisions?: boolean;
  collisionBoundary?: Element | null | Array<Element | null>;
  collisionPadding?: number | Partial<Record<Side, number>>;
  arrowPadding?: number;
  sticky?: "partial" | "always";
  hideWhenDetached?: boolean;
}

const ContextMenuSubContent: React.ForwardRefExoticComponent<
  ContextMenuSubContentProps & React.RefAttributes<HTMLDivElement>
>;

// Short name aliases
const Sub: typeof ContextMenuSub;
const SubTrigger: typeof ContextMenuSubTrigger;
const SubContent: typeof ContextMenuSubContent;

Utility Functions

/**
 * Creates a scoped context for composing with other Radix components
 * Returns a tuple of context creation functions for advanced composition
 */
function createContextMenuScope(): [
  (scope: any) => any,
  (scope?: any) => any
];

Advanced Usage Examples

Complex Context Menu with All Features

import * as ContextMenu from "@radix-ui/react-context-menu";

function ComplexContextMenu() {
  const [checked, setChecked] = React.useState(false);
  const [selection, setSelection] = React.useState("option1");

  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger className="trigger">
        Right click for full menu
      </ContextMenu.Trigger>
      
      <ContextMenu.Portal>
        <ContextMenu.Content className="context-menu">
          <ContextMenu.Label>Edit</ContextMenu.Label>
          <ContextMenu.Item onSelect={() => console.log("Cut")}>
            Cut
          </ContextMenu.Item>
          <ContextMenu.Item onSelect={() => console.log("Copy")}>
            Copy
          </ContextMenu.Item>
          <ContextMenu.Item onSelect={() => console.log("Paste")}>
            Paste
          </ContextMenu.Item>
          
          <ContextMenu.Separator />
          
          <ContextMenu.CheckboxItem 
            checked={checked} 
            onCheckedChange={setChecked}
          >
            <ContextMenu.ItemIndicator>✓</ContextMenu.ItemIndicator>
            Show hidden files
          </ContextMenu.CheckboxItem>
          
          <ContextMenu.Separator />
          
          <ContextMenu.Label>View</ContextMenu.Label>
          <ContextMenu.RadioGroup value={selection} onValueChange={setSelection}>
            <ContextMenu.RadioItem value="option1">
              <ContextMenu.ItemIndicator>•</ContextMenu.ItemIndicator>
              List view
            </ContextMenu.RadioItem>
            <ContextMenu.RadioItem value="option2">
              <ContextMenu.ItemIndicator>•</ContextMenu.ItemIndicator>
              Grid view
            </ContextMenu.RadioItem>
          </ContextMenu.RadioGroup>
          
          <ContextMenu.Separator />
          
          <ContextMenu.Sub>
            <ContextMenu.SubTrigger>More options</ContextMenu.SubTrigger>
            <ContextMenu.Portal>
              <ContextMenu.SubContent>
                <ContextMenu.Item>Export</ContextMenu.Item>
                <ContextMenu.Item>Import</ContextMenu.Item>
              </ContextMenu.SubContent>
            </ContextMenu.Portal>
          </ContextMenu.Sub>
          
          <ContextMenu.Arrow />
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  );
}

Controlled Context Menu

import * as ContextMenu from "@radix-ui/react-context-menu";

function ControlledContextMenu() {
  const [open, setOpen] = React.useState(false);

  return (
    <ContextMenu.Root open={open} onOpenChange={setOpen}>
      <ContextMenu.Trigger>
        Controlled trigger (open: {String(open)})
      </ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Content>
          <ContextMenu.Item onSelect={() => setOpen(false)}>
            Close menu
          </ContextMenu.Item>
        </ContextMenu.Content>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  );
}

Types and Utilities

// Event types for outside interaction detection
type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;
type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>;
type InteractOutsideEvent = PointerDownOutsideEvent | FocusOutsideEvent;

// Positioning and layout types
type Side = "top" | "right" | "bottom" | "left";
type Align = "start" | "center" | "end";
type Direction = "ltr" | "rtl";

// Primitive component type (from @radix-ui/react-primitive)
type Primitive = {
  span: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"span"> & { asChild?: boolean }>;
  div: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"div"> & { asChild?: boolean }>;
  svg: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"svg"> & { asChild?: boolean }>;
};

// Menu primitive types (from @radix-ui/react-menu)
type MenuPrimitive = {
  Content: React.ForwardRefExoticComponent<MenuContentProps>;
  Item: React.ForwardRefExoticComponent<MenuItemProps>;
  CheckboxItem: React.ForwardRefExoticComponent<MenuCheckboxItemProps>;
  RadioGroup: React.ForwardRefExoticComponent<MenuRadioGroupProps>;
  RadioItem: React.ForwardRefExoticComponent<MenuRadioItemProps>;
  ItemIndicator: React.ForwardRefExoticComponent<MenuItemIndicatorProps>;
  Group: React.ForwardRefExoticComponent<MenuGroupProps>;
  Label: React.ForwardRefExoticComponent<MenuLabelProps>;
  Separator: React.ForwardRefExoticComponent<MenuSeparatorProps>;
  Arrow: React.ForwardRefExoticComponent<MenuArrowProps>;
  SubTrigger: React.ForwardRefExoticComponent<MenuSubTriggerProps>;
  SubContent: React.ForwardRefExoticComponent<MenuSubContentProps>;
  Portal: React.ForwardRefExoticComponent<MenuPortalProps>;
};

Styling

The components accept standard HTML attributes and can be styled with CSS. Radix UI provides CSS custom properties for advanced positioning and styling:

.context-menu {
  /* Custom properties available */
  transform-origin: var(--radix-context-menu-content-transform-origin);
  width: var(--radix-context-menu-content-available-width);
  height: var(--radix-context-menu-content-available-height);
}

Accessibility Features

  • Full keyboard navigation with arrow keys, Enter, and Escape
  • ARIA attributes for screen readers
  • Focus management and restoration
  • Support for both right-to-left (RTL) and left-to-right (LTR) text directions
  • Touch device support with long-press gestures
  • Proper focus trapping within open menus