Skip to main content

DHTMLX RichText. Using RichText as an editor for Scheduler example

Live example

RichText can serve as the editor inside another component. This demo embeds it in a DHTMLX Scheduler event form, so opening an event turns its details field into an editor with formatting, lists, and links. Saving the form writes the formatted content back onto the event.

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

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

scheduler.plugins({
  tooltip: true
});

scheduler.config.header = [
    "day",
    "week",
    "month",
    "date",
    "prev",
    "today",
    "next"
];
scheduler.config.wide_form = true;
scheduler.keys.edit_save = -1; // prevent closing lightbox with enter
scheduler.config.lightbox.sections = [
    { name: "Details", map_to: "details", type: "custom_editor", focus: true },
    { name: "time", height: 72, type: "time", map_to: "auto" }
];

// template for event text
scheduler.templates.event_text = function (start, end, event) {
    return `${event.text}<br>
    ${event.details}`
}

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

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

scheduler.init('scheduler_here', new Date(2022, 3, 20), "week");

scheduler.parse([
    { start_date: "2022-04-18 09:00", end_date: "2022-04-18 19:00", text: "Customer Service, Tax Filing, Design", "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>` },
    { start_date: "2022-04-20 10:00", end_date: "2022-04-21 16:00", text: "IT Support, Software, Website", "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>` },
    { start_date: "2022-04-21 06:00", end_date: "2022-04-21 19:00", text: "HR, SEO, Content", "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>` },
    { start_date: "2022-04-23 16:00", end_date: "2022-04-23 17:00", text: "Data Entry, Translation, Design", "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>` },
    { start_date: "2022-04-22 09:00", end_date: "2022-04-22 18:00", text: "Market Research, Tax, Quality", "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>` }
]);

<div id="scheduler_here" class="dhx_cal_container" style='width:100%; height:100%;'></div>

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

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

	ol,
	ul {
		padding: 0 15px;
		margin: 0;
	}

	.dhx_wrap_section:has(#richtext_container) .dhx_cal_lsection {
		width: 0;
		padding: 0;
	}

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

	.dhx_cal_lcontrols .dhx_btn_set.dhx_delete_btn_set,
	.dhx_delete_btn_set:hover {
		padding: 2px 6px;
		border: 1px solid var(--dhx-scheduler-base-colors-error)
	}
</style>

Use case

Use it when an event needs more than a one-line note, like a calendar where each entry carries a formatted agenda, a checklist, or links. Scheduler handles the calendar and the event form, and RichText handles the formatted details inside it. The two connect through a custom Scheduler 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 scheduler.form_blocks["custom_editor"] with render, set_value, get_value, and focus, then list it in scheduler.config.lightbox.sections.
  • Mount the editor on open: in set_value, call new richtext.Richtext("#richtext_container", { value, toolbar }) so the form shows the event's saved details.
  • Save the content back: in get_value, return rtext.getValue(). Scheduler stores that value in the event'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: the section's map_to: "details" links the editor to the event's details property, which also feeds the event and tooltip templates.

API reference

Additional resources