DHTMLX Kanban. Limits for columns and swimlanes (WIP validation) example
Work-in-progress (WIP) limits are a core Kanban practice that prevents overloading any single stage. By capping how many cards a column or swimlane can hold, teams maintain flow and catch bottlenecks early. Visual indicators in the column header signal when limits are approached or exceeded.
Live example
const { Kanban, Toolbar, defaultEditorShape } = kanban;
const columns = [
{
label: "Backlog",
id: "backlog"
},
{
label: "In progress",
id: "inprogress",
limit: 2, // a limit for the column
strictLimit: true
},
{
label: "Testing",
id: "testing",
limit: {
// limits for swimlanes
feature: 2,
task: 2
},
},
{
label: "Done",
id: "done"
}
];
const board = new Kanban("#root", {
columns,
cards,
rows,
rowKey: "type",
cardShape,
editorShape: defaultEditorShape,
});
new Toolbar("#toolbar", { api: board.api });
<!-- 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 rows = [
{
label: "Feature",
id: "feature",
},
{
label: "Task",
id: "task",
},
];
const cards = [
{
id: 1,
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 demo sets limit and strictLimit on columns. The "In progress" column uses limit: 2 with strictLimit: true, which blocks any card from being moved into that column once it holds 2 cards. The "Testing" column uses an object-style limit { feature: 2, task: 2 } to set per-swimlane limits - each row within the column gets its own cap. Column headers automatically display the current count against the limit.
Solution overview
- Add
limit: <number>to a column definition for an overall column WIP limit - Set
strictLimit: trueto block moves that would exceed the limit (without it, the limit is advisory only) - Use
limit: { <rowId>: <number> }for per-swimlane limits within a column - Column headers display the count/limit ratio automatically
Key points
- Limits are visual by default: The column header shows the card count vs. limit, but cards can still be moved in. Set
strictLimit: trueto block moves that would exceed the limit - Per-swimlane limits use row IDs: The keys in the object-style limit must match the
idvalues of your rows
API reference
- columns: Column configuration including
limitandstrictLimitproperties - rows: Swimlane (row) configuration