DHTMLX Kanban. Backend example
A client-side Kanban loses all changes on page reload. Connecting to a backend persists cards, columns, and rows in a database, so the board state survives across sessions and is accessible by any client.
Live example
const { Kanban, Toolbar, RestDataProvider, defaultEditorShape, defaultCardShape } = kanban;
// Check Node.js backend repository here - https://github.com/web-widgets/kanban-node
// Check Go backend repository here - https://github.com/web-widgets/kanban-go
const url = "https://docs.dhtmlx.com/kanban-backend";
const restProvider = new RestDataProvider(url);
const cardShape = {
...defaultCardShape,
label: true,
description: true,
progress: true,
start_date: true,
end_date: true,
priority: true,
color: true,
cover: true,
attached: true,
users: {
show: true,
values: users
}
};
const editorShape = [
...defaultEditorShape,
{
key: "attached",
type: "files",
label: "Files",
uploadURL: url + "/uploads",
},
];
const send = (partUrl, method, data) => {
const headers = {
"Content-Type": "application/json",
};
const req = {
method,
headers,
};
if (data) {
req.body = typeof data === "object" ? JSON.stringify(data) : data;
}
return fetch(`${url}/${partUrl}`, req).then(res => res.json());
}
Promise.all([
restProvider.getCards(),
restProvider.getColumns(),
restProvider.getRows(),
]).then(([cards, columns, rows]) => {
const board = new Kanban("#root", {
cards,
columns,
rows,
rowKey: "row",
cardShape,
editorShape,
});
board.api.setNext(restProvider);
new Toolbar("#toolbar", { api: board.api });
board.api.on('move-column', (ev) => {
send(`columns/${ev.id}/move`, "PUT", ev);
});
board.api.on('move-row', (ev) => {
send(`rows/${ev.id}/move`, "PUT", ev);
});
});<!-- 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",
},
];
</script>The code uses RestDataProvider to load initial data via getCards, getColumns, and getRows, then connects the board to the backend with board.api.setNext(restProvider). This single call routes all board mutations (add, update, delete, move for cards, columns, and rows) through the REST provider automatically. The editor includes a type: "files" field with uploadURL for file attachment support.
Solution overview
- Create a
RestDataProviderwith your backend URL - Load initial data with
Promise.all([getCards(), getColumns(), getRows()]) - Initialize the board with the loaded data
- Connect to the backend:
board.api.setNext(restProvider)
Key points
setNexthandles all operations: After callingboard.api.setNext(restProvider), all CRUD and move operations for cards, columns, and rows are automatically sent to the backend - no manual event handling needed- File uploads: Add
{ type: "files", uploadURL: url + "/uploads" }toeditorShapefor file attachment support - Backend implementations available: Reference backends are available in Node.js and Go on GitHub
API reference
- RestDataProvider: Built-in REST client for backend communication
- api.setNext: Connects the board to a data provider
Related examples
- Backend with comments and votes
- Real-time multiuser backend
- Undo/redo with backend
- Lazy loading tasks per column