@context-menu-kit/core
Framework-agnostic state and event helpers. Use this package when you want to build your own renderer.
API Reference
Reference for the shared core package, React components, Vue components, styling entry points, and customization hooks.
Framework-agnostic state and event helpers. Use this package when you want to build your own renderer.
React components and render props built on top of the core package.
Vue components and slots built on top of the core package.
pnpm add @context-menu-kit/core
pnpm add @context-menu-kit/core @context-menu-kit/react
pnpm add @context-menu-kit/core @context-menu-kit/vueThe core package stores the active context menu state and notifies subscribers whenever the menu opens or closes.
type ContextMenuItem<T = unknown> = {
id: string
label?: string
disabled?: boolean
children?: ContextMenuItem<T>[]
onClick?: (item: ContextMenuItem) => void
data?: T
}import { openContextMenu } from '@context-menu-kit/core'
openContextMenu({
id: 'file-menu',
x: event.clientX,
y: event.clientY,
items,
event,
meta: {
source: 'file-area',
},
})type ContextMenuOpenOptions = {
id: string
x: number
y: number
items: ContextMenuItem[]
meta?: Record<string, unknown>
event?: MouseEvent
}import { closeContextMenu } from '@context-menu-kit/core'
closeContextMenu()import { getContextMenuState } from '@context-menu-kit/core'
const state = getContextMenuState()import { subscribeContextMenu } from '@context-menu-kit/core'
const unsubscribe = subscribeContextMenu((state) => {
console.log(state)
})
unsubscribe()type ContextMenuState = {
isOpen: boolean
id: string | null
x: number
y: number
items: ContextMenuItem[]
event?: MouseEvent
meta?: Record<string, unknown>
}The React package provides components and render props for common usage.
import {
ContextMenu,
ContextMenuProvider,
closeContextMenu,
type ContextMenuItem,
type ContextMenuProps,
type ContextMenuRenderOptions,
type RenderItemProps,
type RenderBodyProps,
} from '@context-menu-kit/react'
import '@context-menu-kit/react/styles.css'Mount this once around the area that should support context menus. It automatically renders the global menu renderer.
<ContextMenuProvider>
<App />
</ContextMenuProvider>type ContextMenuProps<T = unknown> = {
items: ContextMenuItem<T>[]
children: ReactNode
bodyClass?: string
itemClass?: string
renderItem?: (props: RenderItemProps<T>) => ReactNode
renderBody?: (props: RenderBodyProps<T>) => ReactNode
}<ContextMenu
items={items}
renderItem={({ item, close }) => (
<button
disabled={item.disabled}
onClick={() => {
if (item.disabled) return
item.onClick?.(item)
close()
}}
>
{item.label}
</button>
)}
>
<div>Right click here</div>
</ContextMenu><ContextMenu
items={items}
renderBody={({ items, close }) => (
<div className="my-menu">
{items.map((item) => (
<button
key={item.id}
disabled={item.disabled}
onClick={() => {
if (item.disabled) return
item.onClick?.(item)
close()
}}
>
{item.label}
</button>
))}
</div>
)}
>
<div>Right click here</div>
</ContextMenu>The Vue package provides components and slots for common usage.
import {
ContextMenu,
ContextMenuProvider,
closeContextMenu,
type ContextMenuItem,
type ContextMenuProps,
type ContextMenuSlotProps,
type ContextMenuBodySlotProps,
} from '@context-menu-kit/vue'
import '@context-menu-kit/vue/styles.css'Mount this once around the area that should support context menus. It automatically renders the global menu renderer.
<ContextMenuProvider>
<App />
</ContextMenuProvider>interface ContextMenuProps<T = unknown> {
items: ContextMenuItem<T>[]
bodyClass?: string
itemClass?: string
}<ContextMenu :items="items">
<template #item="{ item, close }">
<button
:disabled="item.disabled"
type="button"
@click="
() => {
if (item.disabled) return
item.onClick?.(item)
close()
}
"
>
{{ item.label }}
</button>
</template>
<div>Right click here</div>
</ContextMenu><ContextMenu :items="items">
<template #body="{ items, close }">
<div class="my-menu">
<button
v-for="item in items"
:key="item.id"
:disabled="item.disabled"
type="button"
@click="
() => {
if (item.disabled) return
item.onClick?.(item)
close()
}
"
>
{{ item.label }}
</button>
</div>
</template>
<div>Right click here</div>
</ContextMenu>React and Vue packages both ship a default stylesheet. Import the stylesheet once in your app, or pass custom class names to replace the default body and item classes.
import '@context-menu-kit/react/styles.css'
import '@context-menu-kit/vue/styles.css'.cmk-body
.cmk-item
.cmk-item:hover
.cmk-item-disabled<ContextMenu
items={items}
bodyClass="my-menu"
itemClass="my-menu-item"
>
<div>Right click here</div>
</ContextMenu><ContextMenu
:items="items"
body-class="my-menu"
item-class="my-menu-item"
>
<div>Right click here</div>
</ContextMenu>