DHTMLX Kanban. Custom template for a task card example
When the built-in card layout doesn't fit your design, you can replace it entirely with a custom HTML template. This gives you full control over card markup, styling, and which data fields appear, while still getting drag-and-drop, selection, and context menu behavior from the Kanban.
Live example
const { Kanban, template, defaultCardShape } = kanban;
const { cards, columns, rows } = getData();
const cardShape = {
...defaultCardShape,
color: true,
};
// escape html characters in a string
function escapeHTML(str) {
return str.replace(/[&<>'"]/g, tag => ({
"&": "&",
"<": "<",
">": ">",
"'": "'",
"\"": """
}[tag] || tag));
}
function cardTemplate({ cardFields, selected }) {
const { label, color } = cardFields;
return `
<div class="myCard ${selected ? "selected" : ""}">
<div class="status-color" style="background:${color}"></div>
<div class="label">${escapeHTML(label)}</div>
<div
class="menu-icon"
data-menu-id=${cardFields.id}
data-ignore-selection="true">
<i class="wxi-dots-v"></i>
</div>
</div>
`;
}
const board = new kanban.Kanban("#root", {
columns,
cards,
cardTemplate: template(card => cardTemplate(card)),
cardShape,
});
<!-- component container -->
<div id="root" style="height: 100%;"></div>
<!-- custom styles -->
<style>
.myCard {
background: #fff;
flex: 1;
display: flex;
align-items: center;
padding: 10px;
border-radius: 6px;
}
.selected {
background-color: #f5f5f5;
}
.myCard .status-color {
border-radius: 50%;
flex: 0 0 30px;
height: 30px;
}
.myCard .label {
padding: 0 10px;
font-size: 15px;
font-weight: 500;
text-transform: capitalize;
flex: 1 1 auto;
}
.myCard .menu-icon {
cursor: pointer;
}
.myCard .menu-icon:hover {
background-color: var(--wx-background-hover);
}
</style>The code defines a cardTemplate function that receives { cardFields, selected } and returns an HTML string with a color dot, label, and menu icon. It's passed to the constructor as cardTemplate: template(fn). The data-menu-id attribute on the menu icon enables the built-in context menu, and data-ignore-selection="true" prevents clicking the menu from triggering card selection. The escapeHTML utility prevents XSS from user-provided card labels.
Solution overview
- Create a template function that accepts
{ cardFields, selected }and returns an HTML string - Wrap it with
kanban.template()and pass ascardTemplateto the constructor - Use
data-menu-id={cardFields.id}on elements that should trigger the context menu - Use
data-ignore-selection="true"on interactive elements that shouldn't trigger card selection - Style cards with your own CSS classes
Key points
template()wrapper is required: The function must be wrapped withkanban.template()data-menu-idenables context menu: Without this attribute on a clickable element, users won't be able to access the card menudata-ignore-selection: Add this to buttons or icons that should be clickable without selecting the cardcardShapestill matters: The full card object is always available incardFieldsregardless ofcardShape, butcardShapeprovides the editor with some settings and optionally data, e.g. thevotesbutton or the user list.- Always escape user content: Card labels are user-provided. Use
escapeHTMLto prevent injection
API reference
- cardTemplate: Custom HTML template for cards
- template: Wraps a function for reactive template rendering
- cardShape: Controls which card fields are available