0
# Radix UI React Context Menu
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: @radix-ui/react-context-menu
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @radix-ui/react-context-menu`
10
11
## Core Imports
12
13
```typescript
14
import * as ContextMenu from "@radix-ui/react-context-menu";
15
```
16
17
Or import specific components:
18
19
```typescript
20
import {
21
ContextMenu,
22
ContextMenuTrigger,
23
ContextMenuContent,
24
ContextMenuItem
25
} from "@radix-ui/react-context-menu";
26
```
27
28
For CommonJS:
29
30
```javascript
31
const ContextMenu = require("@radix-ui/react-context-menu");
32
```
33
34
## Basic Usage
35
36
```typescript
37
import * as ContextMenu from "@radix-ui/react-context-menu";
38
39
function App() {
40
return (
41
<ContextMenu.Root>
42
<ContextMenu.Trigger className="trigger">
43
Right click me
44
</ContextMenu.Trigger>
45
<ContextMenu.Portal>
46
<ContextMenu.Content className="context-menu">
47
<ContextMenu.Item>
48
Cut
49
</ContextMenu.Item>
50
<ContextMenu.Item>
51
Copy
52
</ContextMenu.Item>
53
<ContextMenu.Item>
54
Paste
55
</ContextMenu.Item>
56
<ContextMenu.Separator />
57
<ContextMenu.Item>
58
Delete
59
</ContextMenu.Item>
60
</ContextMenu.Content>
61
</ContextMenu.Portal>
62
</ContextMenu.Root>
63
);
64
}
65
```
66
67
## Architecture
68
69
The context menu system is built around several key architectural components:
70
71
**Foundation Architecture**:
72
- **Menu Primitive Foundation**: Built on @radix-ui/react-menu, inheriting full accessibility and keyboard navigation
73
- **Primitive Component System**: Components extend @radix-ui/react-primitive for composition with `asChild` prop support
74
- **Scoped Context System**: Uses `createContextScope` for isolated context management and safe composition with other Radix components
75
- **Popper Positioning**: Integrates @radix-ui/react-popper for collision detection and smart positioning
76
77
**Interaction Model**:
78
- **Context Management**: React context manages open/closed state across component tree
79
- **Trigger System**: Handles right-click (desktop) and long-press (touch) interactions with 700ms timer
80
- **Virtual Anchor**: Uses virtual reference for positioning menu at mouse cursor location
81
- **Portal Rendering**: Renders content outside DOM tree to avoid z-index and overflow issues
82
- **Focus Management**: Automatic focus trapping, restoration, and roving tabindex for accessibility
83
84
**Component Inheritance**:
85
- Most components extend their @radix-ui/react-menu counterparts and inherit all props
86
- ContextMenuContent omits positioning props (`side`, `sideOffset`, `align`) that are automatically managed
87
- All components support primitive composition via `asChild` prop where applicable
88
89
## Capabilities
90
91
### Root Component
92
93
The main context menu container that manages state and provides context to child components.
94
95
```typescript { .api }
96
/**
97
* Root context menu component
98
*/
99
interface ContextMenuProps {
100
children?: React.ReactNode;
101
onOpenChange?(open: boolean): void;
102
dir?: Direction;
103
modal?: boolean; // default: true
104
}
105
106
const ContextMenu: React.FC<ContextMenuProps>;
107
108
// Short name alias
109
const Root: typeof ContextMenu;
110
111
type Direction = "ltr" | "rtl";
112
```
113
114
### Trigger Component
115
116
Element that triggers the context menu on right-click or long-press.
117
118
```typescript { .api }
119
/**
120
* Context menu trigger element
121
*/
122
interface ContextMenuTriggerProps extends React.ComponentPropsWithoutRef<typeof Primitive.span> {
123
disabled?: boolean;
124
}
125
126
// Note: Primitive.span extends standard HTML span element with asChild support
127
128
const ContextMenuTrigger: React.ForwardRefExoticComponent<
129
ContextMenuTriggerProps & React.RefAttributes<HTMLSpanElement>
130
>;
131
132
// Short name alias
133
const Trigger: typeof ContextMenuTrigger;
134
```
135
136
### Portal Component
137
138
Portal component for rendering menu content outside the DOM tree.
139
140
```typescript { .api }
141
/**
142
* Portal for context menu content
143
*/
144
interface ContextMenuPortalProps {
145
children?: React.ReactNode;
146
container?: HTMLElement | null;
147
}
148
149
const ContextMenuPortal: React.FC<ContextMenuPortalProps>;
150
151
// Short name alias
152
const Portal: typeof ContextMenuPortal;
153
```
154
155
### Content Component
156
157
Main container for menu items with positioning and focus management.
158
159
```typescript { .api }
160
/**
161
* Context menu content container
162
* Extends MenuPrimitive.Content but omits positioning props that are automatically managed
163
*/
164
interface ContextMenuContentProps extends Omit<
165
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content>,
166
"onEntryFocus" | "side" | "sideOffset" | "align"
167
> {
168
onEscapeKeyDown?(event: KeyboardEvent): void;
169
onPointerDownOutside?(event: PointerDownOutsideEvent): void;
170
onFocusOutside?(event: FocusOutsideEvent): void;
171
onInteractOutside?(event: InteractOutsideEvent): void;
172
forceMount?: true;
173
loop?: boolean;
174
onCloseAutoFocus?(event: Event): void;
175
disableOutsidePointerEvents?: boolean;
176
disableOutsideScroll?: boolean;
177
trapFocus?: boolean;
178
// Inherited positioning props (automatically managed)
179
// side: 'right' (fixed)
180
// sideOffset: 2 (fixed)
181
// align: 'start' (fixed)
182
// Collision detection
183
avoidCollisions?: boolean;
184
collisionBoundary?: Element | null | Array<Element | null>;
185
collisionPadding?: number | Partial<Record<Side, number>>;
186
// Advanced positioning
187
arrowPadding?: number;
188
sticky?: "partial" | "always";
189
hideWhenDetached?: boolean;
190
updatePositionStrategy?: "optimized" | "always";
191
}
192
193
const ContextMenuContent: React.ForwardRefExoticComponent<
194
ContextMenuContentProps & React.RefAttributes<HTMLDivElement>
195
>;
196
197
// Short name alias
198
const Content: typeof ContextMenuContent;
199
```
200
201
### Menu Structure Components
202
203
Components for organizing menu items and providing visual structure.
204
205
```typescript { .api }
206
/**
207
* Groups related menu items together
208
*/
209
interface ContextMenuGroupProps extends React.ComponentPropsWithoutRef<"div"> {}
210
211
const ContextMenuGroup: React.ForwardRefExoticComponent<
212
ContextMenuGroupProps & React.RefAttributes<HTMLDivElement>
213
>;
214
215
/**
216
* Accessible label for menu groups
217
*/
218
interface ContextMenuLabelProps extends React.ComponentPropsWithoutRef<"div"> {}
219
220
const ContextMenuLabel: React.ForwardRefExoticComponent<
221
ContextMenuLabelProps & React.RefAttributes<HTMLDivElement>
222
>;
223
224
/**
225
* Visual separator between menu items
226
*/
227
interface ContextMenuSeparatorProps extends React.ComponentPropsWithoutRef<"div"> {}
228
229
const ContextMenuSeparator: React.ForwardRefExoticComponent<
230
ContextMenuSeparatorProps & React.RefAttributes<HTMLDivElement>
231
>;
232
233
/**
234
* Arrow pointing from menu to trigger
235
*/
236
interface ContextMenuArrowProps extends React.ComponentPropsWithoutRef<"svg"> {
237
width?: number;
238
height?: number;
239
}
240
241
const ContextMenuArrow: React.ForwardRefExoticComponent<
242
ContextMenuArrowProps & React.RefAttributes<SVGSVGElement>
243
>;
244
245
// Short name aliases
246
const Group: typeof ContextMenuGroup;
247
const Label: typeof ContextMenuLabel;
248
const Separator: typeof ContextMenuSeparator;
249
const Arrow: typeof ContextMenuArrow;
250
```
251
252
### Menu Item Components
253
254
Interactive components for menu actions and selections.
255
256
```typescript { .api }
257
/**
258
* Basic interactive menu item
259
*/
260
interface ContextMenuItemProps extends React.ComponentPropsWithoutRef<"div"> {
261
disabled?: boolean;
262
onSelect?(event: Event): void;
263
textValue?: string;
264
}
265
266
const ContextMenuItem: React.ForwardRefExoticComponent<
267
ContextMenuItemProps & React.RefAttributes<HTMLDivElement>
268
>;
269
270
/**
271
* Menu item with checkbox functionality
272
*/
273
interface ContextMenuCheckboxItemProps extends React.ComponentPropsWithoutRef<"div"> {
274
checked?: boolean | "indeterminate";
275
onCheckedChange?(checked: boolean): void;
276
disabled?: boolean;
277
onSelect?(event: Event): void;
278
textValue?: string;
279
}
280
281
const ContextMenuCheckboxItem: React.ForwardRefExoticComponent<
282
ContextMenuCheckboxItemProps & React.RefAttributes<HTMLDivElement>
283
>;
284
285
/**
286
* Container for radio menu items
287
*/
288
interface ContextMenuRadioGroupProps extends React.ComponentPropsWithoutRef<"div"> {
289
value?: string;
290
onValueChange?(value: string): void;
291
}
292
293
const ContextMenuRadioGroup: React.ForwardRefExoticComponent<
294
ContextMenuRadioGroupProps & React.RefAttributes<HTMLDivElement>
295
>;
296
297
/**
298
* Menu item with radio button functionality
299
*/
300
interface ContextMenuRadioItemProps extends React.ComponentPropsWithoutRef<"div"> {
301
value: string;
302
disabled?: boolean;
303
onSelect?(event: Event): void;
304
textValue?: string;
305
}
306
307
const ContextMenuRadioItem: React.ForwardRefExoticComponent<
308
ContextMenuRadioItemProps & React.RefAttributes<HTMLDivElement>
309
>;
310
311
/**
312
* Visual indicator for checked/selected states
313
*/
314
interface ContextMenuItemIndicatorProps extends React.ComponentPropsWithoutRef<"span"> {
315
forceMount?: true;
316
}
317
318
const ContextMenuItemIndicator: React.ForwardRefExoticComponent<
319
ContextMenuItemIndicatorProps & React.RefAttributes<HTMLSpanElement>
320
>;
321
322
// Short name aliases
323
const Item: typeof ContextMenuItem;
324
const CheckboxItem: typeof ContextMenuCheckboxItem;
325
const RadioGroup: typeof ContextMenuRadioGroup;
326
const RadioItem: typeof ContextMenuRadioItem;
327
const ItemIndicator: typeof ContextMenuItemIndicator;
328
```
329
330
### Submenu Components
331
332
Components for creating nested menu structures.
333
334
```typescript { .api }
335
/**
336
* Container for submenu functionality
337
*/
338
interface ContextMenuSubProps {
339
children?: React.ReactNode;
340
open?: boolean;
341
defaultOpen?: boolean;
342
onOpenChange?(open: boolean): void;
343
}
344
345
const ContextMenuSub: React.FC<ContextMenuSubProps>;
346
347
/**
348
* Menu item that triggers a submenu
349
*/
350
interface ContextMenuSubTriggerProps extends React.ComponentPropsWithoutRef<"div"> {
351
disabled?: boolean;
352
textValue?: string;
353
}
354
355
const ContextMenuSubTrigger: React.ForwardRefExoticComponent<
356
ContextMenuSubTriggerProps & React.RefAttributes<HTMLDivElement>
357
>;
358
359
/**
360
* Container for submenu items
361
*/
362
interface ContextMenuSubContentProps extends React.ComponentPropsWithoutRef<"div"> {
363
onEscapeKeyDown?(event: KeyboardEvent): void;
364
onPointerDownOutside?(event: PointerDownOutsideEvent): void;
365
onFocusOutside?(event: FocusOutsideEvent): void;
366
onInteractOutside?(event: InteractOutsideEvent): void;
367
forceMount?: true;
368
loop?: boolean;
369
sideOffset?: number;
370
alignOffset?: number;
371
avoidCollisions?: boolean;
372
collisionBoundary?: Element | null | Array<Element | null>;
373
collisionPadding?: number | Partial<Record<Side, number>>;
374
arrowPadding?: number;
375
sticky?: "partial" | "always";
376
hideWhenDetached?: boolean;
377
}
378
379
const ContextMenuSubContent: React.ForwardRefExoticComponent<
380
ContextMenuSubContentProps & React.RefAttributes<HTMLDivElement>
381
>;
382
383
// Short name aliases
384
const Sub: typeof ContextMenuSub;
385
const SubTrigger: typeof ContextMenuSubTrigger;
386
const SubContent: typeof ContextMenuSubContent;
387
```
388
389
### Utility Functions
390
391
```typescript { .api }
392
/**
393
* Creates a scoped context for composing with other Radix components
394
* Returns a tuple of context creation functions for advanced composition
395
*/
396
function createContextMenuScope(): [
397
(scope: any) => any,
398
(scope?: any) => any
399
];
400
```
401
402
## Advanced Usage Examples
403
404
### Complex Context Menu with All Features
405
406
```typescript
407
import * as ContextMenu from "@radix-ui/react-context-menu";
408
409
function ComplexContextMenu() {
410
const [checked, setChecked] = React.useState(false);
411
const [selection, setSelection] = React.useState("option1");
412
413
return (
414
<ContextMenu.Root>
415
<ContextMenu.Trigger className="trigger">
416
Right click for full menu
417
</ContextMenu.Trigger>
418
419
<ContextMenu.Portal>
420
<ContextMenu.Content className="context-menu">
421
<ContextMenu.Label>Edit</ContextMenu.Label>
422
<ContextMenu.Item onSelect={() => console.log("Cut")}>
423
Cut
424
</ContextMenu.Item>
425
<ContextMenu.Item onSelect={() => console.log("Copy")}>
426
Copy
427
</ContextMenu.Item>
428
<ContextMenu.Item onSelect={() => console.log("Paste")}>
429
Paste
430
</ContextMenu.Item>
431
432
<ContextMenu.Separator />
433
434
<ContextMenu.CheckboxItem
435
checked={checked}
436
onCheckedChange={setChecked}
437
>
438
<ContextMenu.ItemIndicator>✓</ContextMenu.ItemIndicator>
439
Show hidden files
440
</ContextMenu.CheckboxItem>
441
442
<ContextMenu.Separator />
443
444
<ContextMenu.Label>View</ContextMenu.Label>
445
<ContextMenu.RadioGroup value={selection} onValueChange={setSelection}>
446
<ContextMenu.RadioItem value="option1">
447
<ContextMenu.ItemIndicator>•</ContextMenu.ItemIndicator>
448
List view
449
</ContextMenu.RadioItem>
450
<ContextMenu.RadioItem value="option2">
451
<ContextMenu.ItemIndicator>•</ContextMenu.ItemIndicator>
452
Grid view
453
</ContextMenu.RadioItem>
454
</ContextMenu.RadioGroup>
455
456
<ContextMenu.Separator />
457
458
<ContextMenu.Sub>
459
<ContextMenu.SubTrigger>More options</ContextMenu.SubTrigger>
460
<ContextMenu.Portal>
461
<ContextMenu.SubContent>
462
<ContextMenu.Item>Export</ContextMenu.Item>
463
<ContextMenu.Item>Import</ContextMenu.Item>
464
</ContextMenu.SubContent>
465
</ContextMenu.Portal>
466
</ContextMenu.Sub>
467
468
<ContextMenu.Arrow />
469
</ContextMenu.Content>
470
</ContextMenu.Portal>
471
</ContextMenu.Root>
472
);
473
}
474
```
475
476
### Controlled Context Menu
477
478
```typescript
479
import * as ContextMenu from "@radix-ui/react-context-menu";
480
481
function ControlledContextMenu() {
482
const [open, setOpen] = React.useState(false);
483
484
return (
485
<ContextMenu.Root open={open} onOpenChange={setOpen}>
486
<ContextMenu.Trigger>
487
Controlled trigger (open: {String(open)})
488
</ContextMenu.Trigger>
489
<ContextMenu.Portal>
490
<ContextMenu.Content>
491
<ContextMenu.Item onSelect={() => setOpen(false)}>
492
Close menu
493
</ContextMenu.Item>
494
</ContextMenu.Content>
495
</ContextMenu.Portal>
496
</ContextMenu.Root>
497
);
498
}
499
```
500
501
## Types and Utilities
502
503
```typescript { .api }
504
// Event types for outside interaction detection
505
type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;
506
type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>;
507
type InteractOutsideEvent = PointerDownOutsideEvent | FocusOutsideEvent;
508
509
// Positioning and layout types
510
type Side = "top" | "right" | "bottom" | "left";
511
type Align = "start" | "center" | "end";
512
type Direction = "ltr" | "rtl";
513
514
// Primitive component type (from @radix-ui/react-primitive)
515
type Primitive = {
516
span: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"span"> & { asChild?: boolean }>;
517
div: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"div"> & { asChild?: boolean }>;
518
svg: React.ForwardRefExoticComponent<React.ComponentPropsWithoutRef<"svg"> & { asChild?: boolean }>;
519
};
520
521
// Menu primitive types (from @radix-ui/react-menu)
522
type MenuPrimitive = {
523
Content: React.ForwardRefExoticComponent<MenuContentProps>;
524
Item: React.ForwardRefExoticComponent<MenuItemProps>;
525
CheckboxItem: React.ForwardRefExoticComponent<MenuCheckboxItemProps>;
526
RadioGroup: React.ForwardRefExoticComponent<MenuRadioGroupProps>;
527
RadioItem: React.ForwardRefExoticComponent<MenuRadioItemProps>;
528
ItemIndicator: React.ForwardRefExoticComponent<MenuItemIndicatorProps>;
529
Group: React.ForwardRefExoticComponent<MenuGroupProps>;
530
Label: React.ForwardRefExoticComponent<MenuLabelProps>;
531
Separator: React.ForwardRefExoticComponent<MenuSeparatorProps>;
532
Arrow: React.ForwardRefExoticComponent<MenuArrowProps>;
533
SubTrigger: React.ForwardRefExoticComponent<MenuSubTriggerProps>;
534
SubContent: React.ForwardRefExoticComponent<MenuSubContentProps>;
535
Portal: React.ForwardRefExoticComponent<MenuPortalProps>;
536
};
537
```
538
539
## Styling
540
541
The components accept standard HTML attributes and can be styled with CSS. Radix UI provides CSS custom properties for advanced positioning and styling:
542
543
```css
544
.context-menu {
545
/* Custom properties available */
546
transform-origin: var(--radix-context-menu-content-transform-origin);
547
width: var(--radix-context-menu-content-available-width);
548
height: var(--radix-context-menu-content-available-height);
549
}
550
```
551
552
## Accessibility Features
553
554
- Full keyboard navigation with arrow keys, Enter, and Escape
555
- ARIA attributes for screen readers
556
- Focus management and restoration
557
- Support for both right-to-left (RTL) and left-to-right (LTR) text directions
558
- Touch device support with long-press gestures
559
- Proper focus trapping within open menus