Skip to main content

ContextMenu

Right-click menu wrapper that resolves the clicked card and dispatches built-in actions. Wrap your <Kanban> in <ContextMenu> to get edit, duplicate, and delete on right-click with zero configuration. Extend it with custom entries and gate it per card.

The same menu instance also backs the per-card ... button when card.menu is enabled on <Kanban>.

Usage

import { ContextMenu } from "@svar-uisvelte-kanban";

Props

PropTypeDefaultDescription
apiKanbanInstanceApi | nullnullKanban instance for card lookup and action dispatch. Falls back to internal context if omitted.
optionsany[][]Menu items. Falls back to getMenuOptions() when empty.
resolver(card: KanbanCard, ev: MouseEvent) => any | nullnullGate called after card resolution. Return falsy to suppress the menu for that card.
filter(item: any, card: KanbanCard) => boolean | nullnullPer-item visibility filter. Return false to hide an item for the current card.
atstring"point"Menu placement mode.
onclick(e: any) => voidundefinedFires after built-in handling. Receives { action, context } where action.id is the item id.
cssstringundefinedExtra CSS class forwarded to the inner menu.
childrenSnippet-Wrapped content, typically <Kanban>.

Methods

MethodSignatureDescription
showshow(ev: Event, obj?: any)Opens the menu programmatically. Use from a custom trigger button.

Built-in item IDs

IDTextDispatches
edit-cardEdit cardselect-card with card id
duplicate-cardDuplicate cardduplicate-card with card id
delete-cardDelete carddelete-card with card id

Custom item IDs don't auto-dispatch. Handle them in onclick.

Example

Default right-click menu:

<ContextMenu {api}>
<Kanban bind:this={api} {cards} {columns} />
</ContextMenu>
{#if api}<Editor {api} />{/if}

Extended menu with a custom action:

<script>
import { Kanban, ContextMenu, getMenuOptions } from "@svar-uisvelte-kanban";

let api = $state();
const options = [
...getMenuOptions(),
{ id: "archive", text: "Archive", icon: "wxi-empty" },
];

function onclick({ action }) {
if (action.id === "archive") {
api.exec("update-card", {
id: action.context.id,
card: { archived: true },
});
}
}
</script>

<ContextMenu {api} {options} {onclick}>
<Kanban bind:this={api} {cards} {columns} />
</ContextMenu>

Gated menu - block for read-only cards, hide delete for locked cards:

<ContextMenu
{api}
resolver={(card) => !card.readOnly}
filter={(item, card) => !(card.locked && item.id === "delete-card")}
>
<Kanban bind:this={api} {cards} {columns} />
</ContextMenu>