Skip to main content

DHTMLX Kanban. Keep sort order example

Sorting cards within columns is useful for prioritization, but by default the sort order resets when cards are added or moved. Persistent sorting keeps the chosen order intact even as the board changes, automatically placing new or moved cards in the correct position.

Live example

const { Kanban, Toolbar, defaultEditorShape } = kanban;

const board = new Kanban("#root", {
    columns,
    cards,
    rows,
    rowKey: "type",
    cardShape,
    editorShape: defaultEditorShape,
});
new Toolbar("#toolbar", { api: board.api });

setTimeout(() => board.api.exec("set-sort", { by: "label", preserve: true }));
<!-- 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", value: 1 },
				{ id: 2, color: "#FFC975", label: "Medium", value: 2 },
				{ id: 3, color: "#65D3B3", label: "Low", value: 3 },
			],
		},
		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",
            start_date: new Date("01/01/2021"),
		},
		{
			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 calls board.api.exec("set-sort", { by: "label", preserve: true }) after initialization (wrapped in setTimeout to ensure the board is rendered). The preserve: true flag makes the sort persistent. Any new cards added to the board or cards moved between columns are automatically sorted by label within their column. Without preserve, sorting is a one-time operation.

Solution overview

  1. Initialize the board normally
  2. Call board.api.exec("set-sort", { by: "label", preserve: true }) to apply persistent sorting
  3. Use setTimeout to ensure the board is fully rendered before applying the sort

Key points

  • preserve: true is the key: Without it, set-sort only sorts once. New or moved cards won't respect the order
  • Sort by any card field: The by parameter accepts any card property name: "label", "start_date", "priority", etc.
  • Drag reordering is overridden: With persistent sorting active, manually dragging cards to reorder within a column will be overridden by the sort. The card snaps back to its sorted position
  • setTimeout timing: The sort must be applied after the board renders. Calling it synchronously during initialization may not work

API reference

  • api.exec: Triggers internal events including set-sort

Additional resources