Skip to main content

DHTMLX Kanban. Custom context menu example

The default card menu offers basic actions (duplicate, delete), but workflows often need context-specific options: setting progress, changing assignees, or applying labels. Custom menus let you define different menu items per card and per column, with direct access to card/column data in the handlers.

Live example

const { Kanban, getDefaultCardMenuItems } = kanban;

const board = new Kanban("#root", {
	columns,
	cards,
	rows,
	rowKey: "type",
	cardShape: {
		...cardShape,
		menu: {
			show: true,
			items: ({ card, readonly }) => {
				const defaultMenuItems = getDefaultCardMenuItems({
					card,
					readonly,
				});

				if (card.column === "backlog") {
					return defaultMenuItems;
				}

				return [
					{
						id: "set-edit",
						text: "Edit",
						icon: "wxi-edit",
					},
					{
						id: "progress",
						text: "Set progress",
						icon: "wxi-edit",
						onClick: ({ card }) => {
							board.updateCard({
								id: card.id,
								card: { ...card, progress: 100 },
							});
						},
					},
				];
			},
		},
	},
	columnShape: {
		menu: {
			items: ({ column }) => {
				const items = [
					{
						id: "delete-card",
						icon: "wxi-delete",
						text: "Remove card",
						onClick: ({ column }) => {
							board.deleteCard({
								id: board.getAreaCards(column.id)[0].id,
							});
						},
					},
				];
				if (column.id === "backlog") {
					items.push({
						id: "add-card",
						icon: "fas fa-plus",
						text: "Add card",
					});
				}

				return items;
			},
		},
	},
});

new kanban.Toolbar("#toolbar", {
	api: board.api,
	items: ["search", "spacer", "sort", "addColumn", "addRow"],
});
<!-- font awesome icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<!-- component containers  -->
<div id="toolbar"></div>
<div id="root" style="height: calc(100% - 56px);"></div>

<!-- dataset -->

<script>
const users = [
		{
			id: 1,
			label: "Steve Smith",
			avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-1.jpg",
		},
		{
			id: 2,
			label: "Aaron Long",
			avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-2.jpg",
		},
		{
			id: 3,
			label: "Angela Allen",
			avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-3.jpg",
		},
		{
			id: 4,
			label: "Angela Long",
			avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-4.jpg",
		},
		{
			id: 5,
			label: "John Doe",
		},
	];

	const cardShape = {
		label: true,
		description: true,
		progress: true,
		start_date: true,
		end_date: true,
		users: {
			show: true,
			values: users,
		},
		priority: {
			show: true,
			values: [
				{ id: 1, color: "#FF5252", label: "High" },
				{ id: 2, color: "#FFC975", label: "Medium" },
				{ id: 3, color: "#65D3B3", label: "Low" },
			],
		},
		color: true,
		menu: true,
		cover: true,
		attached: false,
	};

	const columns = [
		{
			label: "Backlog",
			id: "backlog",
		},
		{
			label: "In progress",
			id: "inprogress",
		},
		{
			label: "Testing",
			id: "testing",
		},
		{
			label: "Done",
			id: "done",
		},
	];

	const rows = [
		{
			label: "Feature",
			id: "feature",
		},
		{
			label: "Task",
			id: "task",
		},
	];

	const cards = [
		{
			label: "Integration with Angular/React",
			priority: 1,
			color: "#65D3B3",
			start_date: new Date("01/07/2021"),
			users: [3, 2],
			column: "backlog",
			type: "feature",
		},
		{
			label: "Archive the cards/boards ",
			priority: 3,
			color: "#58C3FE",
			users: [5],
			progress: 1,
			column: "backlog",
			type: "feature",
		},
		{
			label: "Searching and filtering",
			priority: 1,
			color: "#58C3FE",
			start_date: new Date("01/09/2021"),
			users: [3, 1],
			progress: 1,
			column: "backlog",
			type: "task",
		},
		{
			label: "Set the tasks priorities",
			color: "#FFC975",
			start_date: new Date("12/21/2020"),
			users: [4],
			progress: 75,
			column: "inprogress",
			type: "feature",
			attached: [
				{
					isCover: true,
					coverURL:
						"https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-1.jpg",
					previewURL:
						"https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-1.jpg",
					url: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-1.jpg",
					name: "img-1.jpg",
				},
			],
		},
		{
			label: "Custom icons",
			color: "#65D3B3",
			start_date: new Date("01/07/2021"),
			users: [3, 2],
			column: "inprogress",
			type: "task",
		},
		{
			label: "Integration with Gantt",
			color: "#FFC975",
			start_date: new Date("12/21/2020"),
			users: [4],
			progress: 75,
			column: "inprogress",
			type: "task",
		},
		{
			label: "Drag and drop",
			priority: 1,
			color: "#58C3FE",
			users: [3, 1],
			progress: 100,
			column: "testing",
			type: "feature",
		},
		{
			label: "Adding images",
			color: "#58C3FE",
			users: [4],
			column: "testing",
			type: "task",
			attached: [
				{
					isCover: true,
					coverURL:
						"https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-2.jpg",
					previewURL:
						"https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-2.jpg",
					url: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/img-2.jpg",
					name: "img-2.jpg",
				},
			],
		},
		{
			label: "Create cards and lists from the UI and from code",
			priority: 3,
			color: "#65D3B3",
			start_date: new Date("01/07/2021"),
			users: [3, 2],
			column: "done",
			type: "feature",
		},
		{
			label: "Draw swimlanes",
			color: "#FFC975",
			users: [2],
			column: "done",
			type: "feature",
		},
		{
			label: "Progress bar",
			priority: 1,
			color: "#FFC975",
			start_date: new Date("12/9/2020"),
			users: [1, 4, 3],
			progress: 100,
			column: "done",
			type: "task",
		},
	];
</script>

The code customizes both card and column menus. The card menu.items is a function that checks card.column. Backlog cards get the default menu (via getDefaultCardMenuItems), while other cards get a custom menu with "Edit" and "Set progress" actions. The column menu uses a function that always includes a "Remove card" item and conditionally adds "Add card" only for the Backlog column. Menu items support icon, text, id, and onClick properties.

Solution overview

  1. Set cardShape.menu.items to a function receiving { card, readonly } and returning menu items
  2. Use getDefaultCardMenuItems({ card, readonly }) to include default items when needed
  3. Add custom items with onClick handlers that call Kanban methods
  4. Set columnShape.menu.items to a function receiving { column } for column-specific menus
  5. Use built-in action IDs like "set-edit" and "add-card" to trigger standard Kanban actions

Key points

  • getDefaultCardMenuItems as a starting point: Import it from the Kanban package to extend rather than replace the default menu
  • Function-based items: Using a function instead of a static array lets you return different menus per card/column based on their data
  • Built-in action IDs: Menu items with id: "set-edit" or id: "add-card" trigger the corresponding Kanban action automatically. No onClick needed
  • Custom actions need onClick: For custom items like "Set progress", define an onClick that calls board.updateCard or other API methods
  • Font Awesome icons: The demo loads Font Awesome for "fas fa-plus" icon class. Use any icon library or the built-in "wxi-" icon classes

API reference

Additional resources