Skip to main content

DHTMLX RichText. Using RichText as an editor for Gantt example

Live example

RichText can serve as the editor inside another component. This demo embeds it in a DHTMLX Gantt task form: opening a task turns its details field into an editor with formatting, lists, and links, and saving writes the content back onto the task.

const toolbar = [
    "bold",
    "italic",
    "underline",
    "separator",
    "link",
    "separator",
    "fullscreen",
    "bulleted-list",
    "numbered-list"
];

let rtext = null;
gantt.form_blocks["custom_editor"] = {
    render: function (sns) {
        return `<div style="height:350px;width:100%" id="richtext_container"></div>`;
    },
    set_value: function (node, value, task) {
        if (rtext) {
            rtext.destructor();
            rtext = null;
        }
        rtext = new richtext.Richtext("#richtext_container", {
            value: value ?? "default text details",
            toolbar
        });
    },
    get_value: function (node, task) {
        return rtext.getValue();
    },
    focus: function (node) {
    }
};

gantt.plugins({
  tooltip: true
});

gantt.config.wide_form = true;
gantt.keys.edit_save = -1; // prevent closing lightbox with enter
gantt.config.lightbox.sections = gantt.config.lightbox.project_sections = [
    { name: "Details", map_to: "details", type: "custom_editor", focus: true },
    { name: "time", type: "duration", map_to: "auto" }
];

// template for tooltips
gantt.templates.tooltip_text = function(start,end,task){
    return task.details
};

// destroy richtext editor
gantt.attachEvent("onAfterLightbox", function () {
    if (rtext) {
        rtext.destructor();
        rtext = null;
    }
});

const data = {
    tasks: [
        { id: "10", text: "Project #1", start_date: "01-04-2025", duration: 3, progress: 0.4, open: true, details: `<ol><li><span style="font-weight:bold;">Customer Service and Lead Generation</span></li><li><span style="font-weight:bold;">Tax Preparation and Filing</span><ul><li>Social Media Monitoring and Reputation Management</li></ul></li><li><span style="font-weight:bold;">Creative and Design Work</span><ul><li>Product Design and Prototyping</li><li>Animation and Motion Graphics</li></ul></li><li><span style="font-weight:bold;">Patent and Intellectual Property Management</span></li></ol>` },
        { id: "1", text: "Task #1", start_date: "02-04-2025", duration: 2, progress: 0.6, parent: "10", details: `<ol><li><span style="font-weight:bold;">IT Support and Helpdesk Services</span><ul><li>Technical Support for End Users</li></ul></li><li><span style="font-weight:bold;">Software Development and Maintenance</span><ul><li>Training and E-Learning Content Development</li></ul></li><li><span style="font-weight:bold;">Website Development and Management</span></li></ol>` },
        { id: "2", text: "Task #2", start_date: "01-04-2025", duration: 2, progress: 0.6, parent: "10", details: `<ol><li><span style="font-weight:bold;">Human Resources and Recruitment Assistance</span><ul><li>Patent and Intellectual Property Management</li></ul></li><li><span style="font-weight:bold;">Search Engine Optimization (SEO) Services</span><ul><li>Business Intelligence and Data Analytics</li></ul></li><li><span style="font-weight:bold;">Content Writing and Copywriting</span></li></ol>` },
        { id: "20", text: "Project #2", start_date: "01-04-2025", duration: 3, progress: 0.4, type: "project", open: true, details: `<ol><li><span style="font-weight:bold;">Customer Service and Lead Generation</span></li><li><span style="font-weight:bold;">Tax Preparation and Filing</span><ul><li>Social Media Monitoring and Reputation Management</li></ul></li><li><span style="font-weight:bold;">Creative and Design Work</span><ul><li>Product Design and Prototyping</li><li>Animation and Motion Graphics</li></ul></li><li><span style="font-weight:bold;">Patent and Intellectual Property Management</span></li></ol>` },
        { id: "3", text: "Task #3", start_date: "02-04-2025", duration: 2, progress: 0.6, parent: "20", details: `<ol><li><span style="font-weight:bold;">Data Entry and Database Management</span><ul><li>Legal Advisory and Contract Management</li><li>Environmental Compliance and Sustainability Services</li><li>Event Marketing and Promotions</li></ul></li><li><span style="font-weight:bold;">Translation and Localization Services</span></li><li><span style="font-weight:bold;">Creative and Design Work</span></li></ol>` },
        { id: "4", text: "Task #4", start_date: "01-04-2025", duration: 2, progress: 0.6, parent: "20", details: `<ol><li><span style="font-weight:bold;">Market Research and Analysis</span></li><li><span style="font-weight:bold;">Tax Preparation and Filing</span><ul><li>Public Relations and Media Outreach</li></ul></li><li><span style="font-weight:bold;">Quality Assurance and Testing</span></li></ol>` },
    ],
    links: [
        { id: 1, source: 1, target: 2, type: "0" },
        { id: 2, source: 2, target: 3, type: "0" },
        { id: 3, source: 3, target: 4, type: "0" },
    ]
}


gantt.init("gantt_here");
gantt.parse(data);

<div id="gantt_here" style="width:100%; height:100%;"></div>

<style>
body,
	html {
		width: 100%;
		height: 100%;
		margin: unset;
	}


	#richtext_container {
		--wx-background-alt: #FFFFFF;
	}

	.gantt_wrap_section:has(#richtext_container) .gantt_cal_lsection {
		width: 0;
		padding: 0;
	}

	.wx-editor-wrapper {
		border-bottom: var(--wx-border);
	}

	.gantt_cal_lcontrols .gantt_btn_set.gantt_delete_btn_set,
	.gantt_delete_btn_set:hover {
		padding: 2px 6px;
		border: 1px solid var(--dhx-gantt-base-colors-error)
	}
</style>

Use case

Use it when a task needs more than a plain-text note, like a project plan where each task carries a formatted brief, a checklist, or links to specs. Gantt handles the schedule and the task form, and RichText handles the formatted details inside it. The two connect through a custom Gantt lightbox section that mounts the editor and reads its value on save. To make it yours, create the editor in the section's set_value with your toolbar, and return rtext.getValue() from get_value.

How to do this in your app

  • Register a custom lightbox section: define gantt.form_blocks["custom_editor"] with render, set_value, get_value, and focus, then list it in gantt.config.lightbox.sections.
  • Mount the editor on open: in set_value, call new richtext.Richtext("#richtext_container", { value, toolbar }) so the form shows the task's saved details.
  • Save the content back: in get_value, return rtext.getValue(). Gantt stores that value in the task's mapped field (details).
  • Trim the toolbar: pass a short toolbar array (bold, italic, underline, link, lists, fullscreen) to fit the compact form.

Good to know

  • Destroy the editor before reusing the container: the demo calls rtext.destructor() and clears the reference before creating a new instance and after the lightbox closes, so each open starts clean.
  • Preserve intentionally empty content: use value ?? "default text details" so the fallback applies only when the mapped value is missing, not when it is an empty string.
  • get_value reads live from the editor: it calls getValue() at save time, so the returned HTML reflects the latest edits.
  • The details field is mapped, not hardcoded: the section's map_to: "details" links the editor to the task's details property, which also feeds the tooltip template.

API reference

Additional resources