Skip to main content
Back to examples
Popular features/Grid sections
Loading live demo…from dhtmlxcode.com
Popular features

Grid sections

Split the chart into a task tree, the schedule, and a pinned KPI panel that share one scrollbar, with draggable splitters between the sections.

gantt.config.date_format         = "%Y-%m-%d";
gantt.config.open_tree_initially = true;
gantt.config.order_branch        = "marker";
gantt.config.row_height          = 38;
gantt.config.bar_height          = 22;
gantt.config.scale_height        = 50;
gantt.config.scales = [
	{ unit: "month", step: 1, format: "%F %Y" },
	{ unit: "week",  step: 1, format: function (d) { return gantt.date.date_to_str("%d %M")(d); } }
];

let AVATARS = {
	logistics: { color: "#2563eb", initials: "LO" },
	it:        { color: "#16a34a", initials: "IT" },
	ops:       { color: "#d97706", initials: "OP" },
	hr:        { color: "#9333ea", initials: "HR" }
};
function money(n) { return "$" + Number(n).toLocaleString("en-US"); }

/* ---------------------------------------------------------------------------
 *  Row control: flag toggle, rendered in the pinned RIGHT grid
 *  (see rightSectionConfig below).
 * ------------------------------------------------------------------------ */
let ICON = {
	star: '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"><path d="M8 2l1.8 3.9 4.2.5-3.1 2.9.8 4.2L8 11.8 4.3 13.4l.8-4.2L2 6.3l4.2-.5z"/></svg>',
	starF:'<svg viewBox="0 0 16 16" fill="currentColor" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"><path d="M8 2l1.8 3.9 4.2.5-3.1 2.9.8 4.2L8 11.8 4.3 13.4l.8-4.2L2 6.3l4.2-.5z"/></svg>'
};

function flagCell(task) {
	return '<span class="flag ' + (task.important ? "on" : "") + '" onclick="toggleFlag(event,' + task.id + ')">' +
		(task.important ? ICON.starF : ICON.star) + "</span>";
}
function toggleFlag(e, id) {
	e.stopPropagation();
	let task = gantt.getTask(id);
	task.important = !task.important;
	gantt.updateTask(id);
}

gantt.templates.task_class = function (start, end, task) {
	return task.important ? "is_important" : "";
};

gantt.config.columns = [
	{ name: "text",       label: "Task", tree: true, width: 240, resize: true },
	{ name: "start_date", label: "Start", align: "center", width: 100, resize: true, template: function (task) {
		return task.type === gantt.config.types.project ? "" : gantt.templates.date_grid(task.start_date, task);
	}},
	{ name: "duration",   label: "Days", align: "center", width: 56, resize: true }
];

/* ---------------------------------------------------------------------------
 *  RIGHT SECTION: a second grid bound to the same task store; the flag
 *  toggle as the leading column, then owner / status / cost.
 * ------------------------------------------------------------------------ */
let rightSectionConfig = {
	columns: [
		{ name: "flag", label: "", align: "center", width: 36, resize: true, template: flagCell },
		{ name: "owner", label: "Owner", width: 110, resize: true, template: function (task) {
			if (!task.team) return "";
			let avatar = AVATARS[task.team];
			return "<span class='gs_owner'><span class='gs_av' style='background:" + avatar.color + "'>" +
				avatar.initials + "</span>" + task.owner + "</span>";
		}},
		{ name: "status", label: "Status", align: "center", width: 96, resize: true, template: function (task) {
			if (task.type === gantt.config.types.project || !task.status) return "";
			let map = { track: "On track", risk: "At risk", late: "Late", done: "Done" };
			return "<span class='gs_status " + task.status + "'>" + map[task.status] + "</span>";
		}},
		{ name: "cost", label: "Budget", align: "right", width: 92, resize: true, template: function (task) {
			return task.cost ? "<span class='gs_cost'>" + money(task.cost) + "</span>" : "";
		}}
	]
};

/* ---------------------------------------------------------------------------
 *  LAYOUT: grid | timeline | pinned grid, one shared vertical scrollbar
 * ------------------------------------------------------------------------ */
gantt.config.layout = {
	css: "gantt_container",
	rows: [
		{ cols: [
			{ view: "grid", width: 420, scrollY: "scrollVer" },
			{ resizer: true, width: 1, group: "vertical", id: "r1" },
			{ view: "timeline", id: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
			{ resizer: true, width: 1, group: "vertical", id: "r2" },
			{ view: "grid", id: "rightGrid", bind: "task", width: 334,
				config: rightSectionConfig, scrollY: "scrollVer", css: "pinned_grid" },
			{ view: "scrollbar", id: "scrollVer", group: "vertical" }
		]},
		{ view: "scrollbar", id: "scrollHor" }
	]
};

/* ---------------------------------------------------------------------------
 *  DATA
 * ------------------------------------------------------------------------ */
let demoData = {
	tasks: [
		{ id: 1,  text: "Warehouse rollout", type: "project", open: true, owner: "Program", team: "ops", status: "track" },

		{ id: 10, text: "Site & facilities", type: "project", parent: 1, open: true, owner: "Ops", team: "ops", status: "risk" },
		{ id: 11, text: "Lease & permits",   parent: 10, start_date: "2026-04-06", duration: 10, progress: 1,   owner: "M. Ortiz",  team: "ops", status: "done",  cost: 42000 },
		{ id: 12, text: "Racking install",   parent: 10, start_date: "2026-04-20", duration: 14, progress: 0.5, owner: "M. Ortiz",  team: "ops", status: "risk",  cost: 88000 },
		{ id: 13, text: "Power upgrade",     parent: 10, start_date: "2026-04-28", duration: 8,  progress: 0.3, owner: "M. Ortiz",  team: "ops", status: "risk",  cost: 64000 },
		{ id: 14, text: "Safety inspection", parent: 10, start_date: "2026-05-11", duration: 4,  progress: 0,   owner: "M. Ortiz",  team: "ops", status: "track", cost: 12000 },
		{ id: 15, text: "Dock door retrofit", parent: 10, start_date: "2026-05-15", duration: 9,  progress: 0.2, owner: "M. Ortiz",  team: "ops", status: "risk",  cost: 37000 },
		{ id: 16, text: "Signage & striping", parent: 10, start_date: "2026-05-26", duration: 5,  progress: 0,   owner: "M. Ortiz",  team: "ops", status: "track", cost: 8500 },

		{ id: 20, text: "IT & systems", type: "project", parent: 1, open: true, owner: "IT", team: "it", status: "track", important: true },
		{ id: 21, text: "Network & WiFi",    parent: 20, start_date: "2026-04-27", duration: 8,  progress: 0.6, owner: "S. Patel",  team: "it",  status: "track", cost: 31000 },
		{ id: 22, text: "WMS deployment",     parent: 20, start_date: "2026-05-07", duration: 16, progress: 0.3, owner: "S. Patel",  team: "it",  status: "track", cost: 120000, important: true },
		{ id: 23, text: "Scanner rollout",    parent: 20, start_date: "2026-05-25", duration: 6,  progress: 0,   owner: "S. Patel",  team: "it",  status: "track", cost: 24000 },
		{ id: 24, text: "Label printer setup", parent: 20, start_date: "2026-05-27", duration: 5, progress: 0,   owner: "S. Patel",  team: "it",  status: "track", cost: 16000 },
		{ id: 25, text: "ERP integration",     parent: 20, start_date: "2026-06-01", duration: 10, progress: 0,  owner: "S. Patel",  team: "it",  status: "risk",  cost: 72000 },
		{ id: 26, text: "Access control setup", parent: 20, start_date: "2026-06-03", duration: 6, progress: 0,  owner: "S. Patel",  team: "it",  status: "track", cost: 19500 },

		{ id: 30, text: "Logistics", type: "project", parent: 1, open: true, owner: "Logistics", team: "logistics", status: "late" },
		{ id: 31, text: "Carrier contracts", parent: 30, start_date: "2026-05-04", duration: 9,  progress: 0.4, owner: "J. Lee",    team: "logistics", status: "late",  cost: 18000 },
		{ id: 32, text: "Inbound test run",  parent: 30, start_date: "2026-05-18", duration: 7,  progress: 0,   owner: "J. Lee",    team: "logistics", status: "track", cost: 9000 },
		{ id: 33, text: "Outbound simulation", parent: 30, start_date: "2026-05-28", duration: 6, progress: 0,   owner: "J. Lee",    team: "logistics", status: "track", cost: 11000 },
		{ id: 34, text: "Peak-volume rehearsal", parent: 30, start_date: "2026-06-08", duration: 5, progress: 0, owner: "J. Lee",    team: "logistics", status: "track", cost: 14000 },
		{ id: 35, text: "Returns process pilot", parent: 30, start_date: "2026-06-09", duration: 4, progress: 0, owner: "J. Lee",    team: "logistics", status: "late",  cost: 7200 },

		{ id: 40, text: "People", type: "project", parent: 1, open: true, owner: "HR", team: "hr", status: "track" },
		{ id: 41, text: "Hiring & training",  parent: 40, start_date: "2026-05-11", duration: 12, progress: 0.2, owner: "R. Kim",    team: "hr",  status: "track", cost: 56000 },
		{ id: 42, text: "Shift scheduling",    parent: 40, start_date: "2026-05-25", duration: 7,  progress: 0,   owner: "R. Kim",    team: "hr",  status: "track", cost: 18000 },
		{ id: 43, text: "Safety certification", parent: 40, start_date: "2026-06-02", duration: 6, progress: 0,  owner: "R. Kim",    team: "hr",  status: "risk",  cost: 15500 }
	],
	links: [
		{ id: 1,  source: 11, target: 12, type: "0" },
		{ id: 2,  source: 11, target: 13, type: "0" },
		{ id: 3,  source: 12, target: 14, type: "0" },
		{ id: 4,  source: 13, target: 14, type: "0" },
		{ id: 18, source: 14, target: 15, type: "0" },
		{ id: 19, source: 15, target: 16, type: "0" },

		{ id: 5,  source: 21, target: 22, type: "0" },
		{ id: 6,  source: 22, target: 23, type: "0" },
		{ id: 7,  source: 22, target: 24, type: "0" },
		{ id: 8,  source: 23, target: 25, type: "0" },
		{ id: 9,  source: 24, target: 25, type: "0" },
		{ id: 20, source: 25, target: 26, type: "0" },

		{ id: 10, source: 31, target: 32, type: "0" },
		{ id: 11, source: 32, target: 33, type: "0" },
		{ id: 12, source: 33, target: 34, type: "0" },
		{ id: 21, source: 34, target: 35, type: "0" },

		{ id: 13, source: 41, target: 42, type: "0" },
		{ id: 22, source: 42, target: 43, type: "0" },

		{ id: 14, source: 12, target: 41, type: "0" },
		{ id: 15, source: 14, target: 32, type: "0" },
		{ id: 16, source: 22, target: 42, type: "0" },
		{ id: 17, source: 23, target: 34, type: "0" }
	]
};

/* ---------------------------------------------------------------------------
 *  ZOOM
 * ------------------------------------------------------------------------ */
gantt.ext.zoom.init({
	levels: [
		{ name: "week",  scale_height: 50, scales: [{ unit: "month", step: 1, format: "%F %Y" }, { unit: "week", step: 1, format: function (d) { return gantt.date.date_to_str("%d %M")(d); } }] },
		{ name: "month", scale_height: 50, scales: [{ unit: "year",  step: 1, format: "%Y" }, { unit: "month", step: 1, format: "%M" }] }
	],
	element: function () { return gantt.$root.querySelector(".gantt_task"); }
});
DHX.zoom.init(gantt, ["week", "month"], "zoom_seg", "footer_scale");
function setZoom(name) { DHX.zoom.set(name); }

/* ---------------------------------------------------------------------------
 *  INIT
 * ------------------------------------------------------------------------ */
gantt.init("gantt_here");
gantt.parse(demoData);
DHX.zoom.set("week");
<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8">
	<title>Grid sections: dhtmlxGantt</title>
	<script src="../../codebase/dhtmlxgantt.js?v=10.0.0"></script>
	<link rel="stylesheet" href="../../codebase/dhtmlxgantt.css?v=10.0.0">
	<link rel="stylesheet" href="../common/demo-controls/dhx_controls.css">
	<script src="../common/demo-controls/dhx_controls.js"></script>
	<link rel="preconnect" href="https://fonts.googleapis.com">
	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
	<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap">
	<style>
		body { display: flex; flex-direction: column; }
		#gantt_here { width: 100%; flex: 1 1 auto; min-height: 0; }

		.footer_note { white-space: nowrap; }

		@media (max-width: 820px) {
			.footer_note { display: none; }
		}

		.gantt_layout_cell.pinned_grid { box-shadow: inset 1px 0 0 var(--dhx-line); }

		.gs_owner { display: inline-flex; align-items: center; gap: 7px; }
		.gs_av {
			width: 22px; height: 22px; border-radius: 50%; flex: none;
			color: #fff; font: 600 10px var(--dhx-font);
			display: inline-flex; align-items: center; justify-content: center;
		}

		.gs_status {
			display: inline-block; padding: 1px 9px; border-radius: 10px;
			font: 600 11px var(--dhx-font);
		}
		.gs_status.track { background: var(--dhx-ok-bg); color: var(--dhx-ok-ink); }
		.gs_status.risk  { background: var(--dhx-warn-bg); color: var(--dhx-warn-ink); }
		.gs_status.late  { background: var(--dhx-danger-bg); color: var(--dhx-danger-ink); }
		.gs_status.done  { background: var(--dhx-neutral-bg); color: var(--dhx-neutral-ink); }

		.gs_cost { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--dhx-ink); }

		.gantt_grid_head_cell { font-weight: 600; }

		.flag { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; vertical-align: middle; cursor: pointer; color: var(--dhx-muted); }
		.flag:hover { color: #f59e0b; }
		.flag.on { color: #f59e0b; }
		.flag svg { width: 15px; height: 15px; }

		.gantt_task_line.is_important { box-shadow: 0 0 0 2px #f59e0b, 0 1px 2px rgba(16,24,40,.18); }
	</style>
</head>
<body>

<div class="dhx_header dhx_header--centered">
	<div class="dhx_seg" id="zoom_seg">
		<button class="dhx_btn" data-zoom="week"  onclick="setZoom('week')">Week</button>
		<button class="dhx_btn" data-zoom="month" onclick="setZoom('month')">Month</button>
	</div>
</div>

<div id="gantt_here"></div>

<div class="dhx_footer">
	<span class="footer_note">Drag the splitters to resize sections. The pinned right panel stays row-aligned with the tree and the schedule.</span>
	<div class="dhx_footer__right"><span id="footer_scale">Week scale</span></div>
</div>


</body>
</html>