or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

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