or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-api.mdfunctional-api.mdindex.mdmenu-bar.mdthemes.md
tile.json

index.mddocs/

0

# Vue3 Context Menu

1

2

Vue3 Context Menu is a comprehensive context menu component library for Vue 3 applications that enables developers to create customizable right-click menus with rich functionality. It offers both functional and component-based APIs for displaying context menus, supports nested submenus and separators, provides multiple built-in themes with both light and dark variants, and includes keyboard navigation support.

3

4

## Package Information

5

6

- **Package Name**: @imengyu/vue3-context-menu

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @imengyu/vue3-context-menu`

10

11

## Core Imports

12

13

```typescript

14

import ContextMenu from '@imengyu/vue3-context-menu';

15

import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css';

16

17

// For functional API

18

import ContextMenu from '@imengyu/vue3-context-menu';

19

20

// For component imports

21

import {

22

ContextMenu as ContextMenuComponent,

23

ContextMenuItem,

24

ContextMenuSeparator,

25

ContextMenuGroup,

26

MenuBar

27

} from '@imengyu/vue3-context-menu';

28

```

29

30

For CommonJS:

31

32

```javascript

33

const ContextMenu = require('@imengyu/vue3-context-menu');

34

require('@imengyu/vue3-context-menu/lib/vue3-context-menu.css');

35

```

36

37

## Basic Usage

38

39

### Installation and Setup

40

41

```typescript

42

import { createApp } from 'vue';

43

import ContextMenu from '@imengyu/vue3-context-menu';

44

import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css';

45

46

const app = createApp(App);

47

app.use(ContextMenu);

48

```

49

50

### Quick Example - Functional API

51

52

```typescript

53

import ContextMenu from '@imengyu/vue3-context-menu';

54

55

function onContextMenu(e: MouseEvent) {

56

e.preventDefault();

57

58

ContextMenu.showContextMenu({

59

x: e.x,

60

y: e.y,

61

items: [

62

{

63

label: "Copy",

64

icon: "copy-icon",

65

onClick: () => console.log("Copy clicked")

66

},

67

{

68

label: "Edit",

69

children: [

70

{ label: "Cut", onClick: () => console.log("Cut clicked") },

71

{ label: "Paste", onClick: () => console.log("Paste clicked") },

72

]

73

},

74

{ divided: true, label: "Delete", onClick: () => console.log("Delete clicked") }

75

]

76

});

77

}

78

```

79

80

### Quick Example - Component API

81

82

```vue

83

<template>

84

<div @contextmenu="onRightClick">

85

<context-menu v-model:show="show" :options="menuOptions">

86

<context-menu-item label="Copy" icon="copy-icon" @click="handleCopy" />

87

<context-menu-separator />

88

<context-menu-group label="Edit">

89

<context-menu-item label="Cut" @click="handleCut" />

90

<context-menu-item label="Paste" @click="handlePaste" />

91

</context-menu-group>

92

</context-menu>

93

</div>

94

</template>

95

96

<script setup>

97

import { ref } from 'vue';

98

99

const show = ref(false);

100

const menuOptions = ref({

101

x: 0,

102

y: 0,

103

zIndex: 1000

104

});

105

106

function onRightClick(e) {

107

e.preventDefault();

108

menuOptions.value.x = e.x;

109

menuOptions.value.y = e.y;

110

show.value = true;

111

}

112

</script>

113

```

114

115

## Architecture

116

117

Vue3 Context Menu is built around several key components:

118

119

- **Functional API**: Global methods for programmatic menu display (`showContextMenu`, `closeContextMenu`)

120

- **Component API**: Vue components for declarative menu construction (`ContextMenu`, `ContextMenuItem`, etc.)

121

- **Theme System**: Built-in themes (default, flat, win10, mac) with light/dark variants

122

- **Position System**: Automatic position adjustment to prevent menu overflow

123

- **Keyboard Navigation**: Full keyboard control support matching Windows menu behavior

124

- **Menu Bar**: Traditional horizontal menu bar component for desktop-style applications

125

126

## Capabilities

127

128

### Functional API

129

130

Core programmatic interface for displaying context menus with full configuration control. Perfect for dynamic menus and event-driven scenarios.

131

132

```typescript { .api }

133

interface ContextMenuGlobal {

134

showContextMenu(options: MenuOptions, customSlots?: Record<string, Slot>): ContextMenuInstance;

135

closeContextMenu(): void;

136

isAnyContextMenuOpen(): boolean;

137

transformMenuPosition(element: HTMLElement, x: number, y: number, container?: HTMLElement): { x: number, y: number };

138

}

139

140

interface MenuOptions {

141

/** Menu items array */

142

items?: MenuItem[];

143

/** Menu display X position */

144

x: number;

145

/** Menu display Y position */

146

y: number;

147

/** X-coordinate offset of submenu and parent menu */

148

xOffset?: number;

149

/** Y-coordinate offset of submenu and parent menu */

150

yOffset?: number;

151

/** Theme name (default, flat, win10, mac, with optional 'dark' suffix) */

152

theme?: string;

153

/** Menu pop-up direction relative to coordinates */

154

direction?: MenuPopDirection;

155

/** Z-index for menu display */

156

zIndex?: number;

157

/** Menu zoom level */

158

zoom?: number;

159

/** Custom CSS class for menu */

160

customClass?: string;

161

/** Enable mouse scroll wheel in menu area */

162

mouseScroll?: boolean;

163

/** Provide space placeholder for up/down buttons */

164

updownButtonSpaceholder?: boolean;

165

/** Element class name to ignore clicks */

166

ignoreClickClassName?: string;

167

/** Close menu when clicking outside */

168

clickCloseOnOutside?: boolean;

169

/** Element class name that closes menu when clicked */

170

clickCloseClassName?: string;

171

/** Custom icon library font class name */

172

iconFontClass?: string;

173

/** Vue Transition props for menu show/hide */

174

menuTransitionProps?: TransitionProps;

175

/** Reserve fixed-width icon area for items without icon */

176

preserveIconWidth?: boolean;

177

/** Enable keyboard control */

178

keyboardControl?: boolean;

179

/** Maximum width of menu (pixels) */

180

maxWidth?: number;

181

/** Maximum height of menu (pixels) */

182

maxHeight?: number;

183

/** Minimum width of menu (pixels) */

184

minWidth?: number;

185

/** Close when user scrolls */

186

closeWhenScroll?: boolean;

187

/** Padding for submenu position adjustment */

188

adjustPadding?: { x: number, y: number } | number;

189

/** Automatically adjust position to prevent overflow */

190

adjustPosition?: boolean;

191

/** Container element for menu mounting */

192

getContainer?: HTMLElement | (() => HTMLElement);

193

/** Event when menu is closing */

194

onClose?: (lastClickItem: MenuItem | undefined) => void;

195

/** Event when clicking outside (when clickCloseOnOutside is false) */

196

onClickOnOutside?: (e: MouseEvent) => void;

197

/** Event for MenuBar left focus move */

198

onKeyFocusMoveLeft?: () => void;

199

/** Event for MenuBar right focus move */

200

onKeyFocusMoveRight?: () => void;

201

}

202

```

203

204

[Functional API](./functional-api.md)

205

206

### Component API

207

208

Vue components for declarative menu construction with full template integration. Ideal for static menus and component-based architectures.

209

210

```typescript { .api }

211

// Main context menu component

212

declare component ContextMenu {

213

props: {

214

options: MenuOptions;

215

show: boolean;

216

};

217

events: {

218

'update:show': (show: boolean) => void;

219

'close': () => void;

220

};

221

}

222

223

// Menu item component

224

declare component ContextMenuItem {

225

props: {

226

label?: string;

227

icon?: string;

228

disabled?: boolean;

229

hidden?: boolean;

230

checked?: boolean;

231

shortcut?: string;

232

};

233

events: {

234

'click': (e: MouseEvent | KeyboardEvent) => void;

235

};

236

}

237

238

// Menu separator component

239

declare component ContextMenuSeparator {

240

// No props

241

}

242

243

// Menu group component for nested submenus

244

declare component ContextMenuGroup {

245

props: {

246

label: string;

247

};

248

// Contains slot for child menu items

249

}

250

```

251

252

[Component API](./component-api.md)

253

254

### Menu Bar

255

256

Traditional horizontal menu bar component for desktop-style applications with dropdown menus.

257

258

```typescript { .api }

259

declare component MenuBar {

260

props: {

261

options: MenuBarOptions;

262

};

263

}

264

265

interface MenuBarOptions extends Omit<MenuOptions, 'x'|'y'|'getContainer'> {

266

mini?: boolean;

267

barPopDirection?: MenuPopDirection;

268

}

269

```

270

271

[Menu Bar](./menu-bar.md)

272

273

### Themes and Styling

274

275

Built-in theme system with light and dark variants for different UI styles.

276

277

```typescript { .api }

278

type ThemeNames =

279

| 'default'

280

| 'default dark'

281

| 'flat'

282

| 'flat dark'

283

| 'win10'

284

| 'win10 dark'

285

| 'mac'

286

| 'mac dark';

287

```

288

289

[Themes and Styling](./themes.md)

290

291

## Types

292

293

### Vue Types

294

295

```typescript { .api }

296

// Vue framework types used throughout the API

297

interface VNode {

298

// Vue virtual node for custom renders

299

}

300

301

interface ComputedRef<T> {

302

// Vue computed reference

303

readonly value: T;

304

}

305

306

interface Slot {

307

// Vue slot function

308

(...args: any[]): VNode[];

309

}

310

```

311

312

### Core Types

313

314

```typescript { .api }

315

type MenuPopDirection = 'br'|'b'|'bl'|'tr'|'t'|'tl'|'l'|'r';

316

317

interface MenuItem {

318

/** Menu item label */

319

label?: string | VNode | ((label: string) => VNode);

320

/** Menu item icon */

321

icon?: string | VNode | ((icon: string) => VNode);

322

/** Custom icon font class name */

323

iconFontClass?: string;

324

/** Reserve fixed-width icon area */

325

preserveIconWidth?: boolean;

326

/** SVG symbol icon reference */

327

svgIcon?: string;

328

/** SVG element properties */

329

svgProps?: SVGAttributes;

330

/** Disable menu item */

331

disabled?: boolean | ComputedRef<boolean>;

332

/** Hide menu item */

333

hidden?: boolean | ComputedRef<boolean>;

334

/** Show check mark */

335

checked?: boolean | ComputedRef<boolean>;

336

/** Shortcut key display text */

337

shortcut?: string;

338

/** Submenu popup direction */

339

direction?: MenuPopDirection;

340

/** Adjust submenu position */

341

adjustSubMenuPosition?: boolean;

342

/** Allow click when has children */

343

clickableWhenHasChildren?: boolean;

344

/** Close menu on click */

345

clickClose?: boolean;

346

/** Separator display option */

347

divided?: boolean | 'up' | 'down' | 'self';

348

/** Custom CSS class */

349

customClass?: string;

350

/** Maximum height in pixels */

351

maxHeight?: number;

352

/** Maximum width in pixels */

353

maxWidth?: number | string;

354

/** Minimum width in pixels */

355

minWidth?: number | string;

356

/** Click event handler */

357

onClick?: (e?: MouseEvent | KeyboardEvent) => void;

358

/** Submenu close event */

359

onSubMenuClose?: (itemInstance?: MenuItemContext) => void;

360

/** Submenu open event */

361

onSubMenuOpen?: (itemInstance?: MenuItemContext) => void;

362

/** Custom render function */

363

customRender?: VNode | ((item: MenuItem) => VNode);

364

/** Child menu items */

365

children?: MenuItem[];

366

}

367

368

interface ContextMenuInstance {

369

/** Close the menu */

370

closeMenu(fromItem?: MenuItem | undefined): void;

371

/** Check if menu is closed */

372

isClosed(): boolean;

373

/** Get root menu instance */

374

getMenuRef(): ContextSubMenuInstance | undefined;

375

/** Get menu dimensions */

376

getMenuDimensions(): { width: number, height: number };

377

}

378

379

interface ContextSubMenuInstance {

380

/** Get submenu root element */

381

getSubmenuRoot(): HTMLElement | undefined;

382

/** Get menu container element */

383

getMenu(): HTMLElement | undefined;

384

/** Get child menu item by index */

385

getChildItem(index: number): MenuItemContext | undefined;

386

/** Get menu dimensions */

387

getMenuDimensions(): { width: number, height: number };

388

/** Get current scroll value */

389

getScrollValue(): number;

390

/** Set scroll value */

391

setScrollValue(v: number): void;

392

/** Get scroll height */

393

getScrollHeight(): number;

394

/** Force adjust position */

395

adjustPosition(): void;

396

/** Get maximum height */

397

getMaxHeight(): number;

398

/** Get current position */

399

getPosition(): { x: number, y: number };

400

/** Set position */

401

setPosition(x: number, y: number): void;

402

}

403

404

interface MenuItemContext {

405

/** Get submenu instance */

406

getSubMenuInstance(): ContextSubMenuInstance | undefined;

407

/** Show submenu */

408

showSubMenu(): boolean;

409

/** Hide submenu */

410

hideSubMenu(): void;

411

/** Get HTML element */

412

getElement(): HTMLElement | undefined;

413

/** Check if disabled or hidden */

414

isDisabledOrHidden(): boolean;

415

/** Focus item */

416

focus(): void;

417

/** Blur item */

418

blur(): void;

419

/** Click item */

420

click(e: MouseEvent | KeyboardEvent): void;

421

}

422

423

interface SVGAttributes {

424

[key: string]: any;

425

}

426

427

interface TransitionProps {

428

name?: string;

429

mode?: 'in-out' | 'out-in' | 'default';

430

appear?: boolean;

431

css?: boolean;

432

type?: 'transition' | 'animation';

433

duration?: number | { enter: number; leave: number };

434

enterFromClass?: string;

435

enterActiveClass?: string;

436

enterToClass?: string;

437

appearFromClass?: string;

438

appearActiveClass?: string;

439

appearToClass?: string;

440

leaveFromClass?: string;

441

leaveActiveClass?: string;

442

leaveToClass?: string;

443

}

444

```