Skip to main content

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

  1. Add limit: <number> to a column definition for an overall column WIP limit
  2. Set strictLimit: true to block moves that would exceed the limit (without it, the limit is advisory only)
  3. Use limit: { <rowId>: <number> } for per-swimlane limits within a column
  4. 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: true to block moves that would exceed the limit
  • Per-swimlane limits use row IDs: The keys in the object-style limit must match the id values of your rows

API reference

  • columns: Column configuration including limit and strictLimit properties
  • rows: Swimlane (row) configuration

Additional resources