Skip to main content

DHTMLX Kanban. Styling columns and custom column menu example

Color-coding columns helps users instantly identify workflow stages. Combined with a custom column menu, users can change column colors on the fly without editing configuration files, useful for teams that want visual customization at runtime.

Live example

const { Kanban, Toolbar, defaultEditorShape } = kanban;
const { cards, cardShape, rows } = getData();

const columns = [
  {
    label: "Backlog",
    id: "backlog",
    css: "yellow"
  },
  {
    label: "In progress",
    id: "inprogress",
    limit: 3, // a limit for the column
    strictLimit: true,
    css: "red"
  },
  {
    label: "Testing",
    id: "testing",
    limit: {
      // limits for swimlanes
      feature: 2,
      task: 2
    },
    css: "blue"
  },
  {
    label: "Done",
    id: "done",
    css: "green"
  }
];

const board = new Kanban("#root", {
    columns,
    cards,
    rows,
    rowKey:"type",
    columnShape: {
        css: (column, cards) => "gray",
        menu: {
            show: true,
            items: [
                {
                    id: "color",
                    text: "Color",
                    data: [
                        { 
                            id:"yellow", 
                            text: "Yellow",
                            onClick: ({ column }) => changeColumnColor(column, "yellow")
                        },
                        { 
                            id:"red", 
                            text: "Red",
                            onClick: ({ column }) => changeColumnColor(column, "red")
                        },
                        { 
                            id:"green", 
                            text: "Green",
                            onClick: ({ column }) => changeColumnColor(column, "green")
                        },
                        { 
                            id:"blue", 
                            text: "Blue",
                            onClick: ({ column }) => changeColumnColor(column, "blue")
                        }
                    ]
                }
            ]
        }
    },
    editorShape: defaultEditorShape.filter(e => e.key !== "users"),
});

const toolbar = new Toolbar("#toolbar", { api: board.api });

const changeColumnColor = (column, cssClass) => board.updateColumn({ 
    id: column.id,
    column: {
        css: cssClass,
    },
    replace: false
});
<!-- custom styles -->

<style>
.wx-kanban .wx-column {
        padding: 0 10px;
      	border-radius: 5pt;
        margin-top: 8px;
    }
    .wx-kanban .wx-label-line {
        border: none;
    }
  	.gray {
        background: #dadcdd;
	}
    .yellow {
		background: #FFEB84; 
	}
    .red {
        background: #FFA29C;
	}
    .green {
        background: #98EBA5;
	}
    .blue {
        background: #BDE9FD;
	}
</style>

The code applies styling at two levels: static css classes on individual columns (e.g., css: "yellow") and a dynamic css function on columnShape that returns "gray" as a base style. The custom menu is defined in columnShape.menu.items with nested submenu items. Each color option has an onClick handler that calls board.updateColumn with the new CSS class. The replace: false parameter in updateColumn merges the update rather than replacing the entire column object.

Solution overview

  1. Add css: "className" to column definitions for initial colors
  2. Set columnShape.css to a function for dynamic base styling
  3. Define columnShape.menu.items with nested data arrays for submenus
  4. Use onClick handlers that call board.updateColumn({ id, column: { css }, replace: false })
  5. Define matching CSS classes for each color

Key points

  • Two CSS layers: Column-level css and columnShape.css both apply. column.css is added to the element's class list first, followed by the result of columnShape.css. Which class wins a style conflict depends on the order the CSS rules appear in your stylesheet
  • replace: false is the default: updateColumn merges by default. Only the specified properties change. Passing replace: true would replace the entire column object, losing other properties like label and limit
  • Nested menu items: Use the data array property on a menu item to create a submenu (dropdown within dropdown)
  • onClick receives context: Each menu item's onClick gets { column }, the full column object for the clicked column

API reference

Additional resources