How to enable Rich Text in Dynamics CRM using CKEditor

(note:  this was reposted to fix issues in the code from here: , so all the comments related to this post are located at the URL above).

I recently found myself in the position where we needed to submit notes from customer conversations into Dynamics CRM.  I’m a fan of ‘fancy’ text (headings, bullet points, highlighting) to help make the notes much more readable, but Dynamics CRM doesn’t support this out of the box on their website.  Instead of making my notes less fancy, I opted to just enable this capability in Dynamics CRM!  We will be using the CKEditor in this example, you can find it here: .

There are already a few options online for doing this:

In my case, I was looking for something a little simpler where I didn’t need to do synchronization between the nested iFrame and the control that I was trying to replace.  I’m planning on using CKEditor which does a great job replacing controls inline, let’s make that work!

The first step is to create a web resource to hold some JavaScript.  We are going to do everything dynamically in JavaScript so we won’t need any other resources, files, scripts, etc.  You can do this by navigating to the form that you want to change (the one that needs some fancy text!) and open the form editor.  Click the “Form Properties” button on the toolbar, this is where we can add a web resource.  On the dialog that comes up, click “Add”



On the next dialog we hit “New” to add a new web resource, this is the place where we’ll put our JavaScript to convert controls on the page!


On this next dialog (to create a new web resource), we fill out the fields (example below) and can either upload the javascript file or we can paste in the javascript by clicking on the “”text editor”


Now comes the interesting part – what JavaScript should we be using anyway?  Well, the first step is importing the CKEditor library.  We can’t just do a straight import because it’s considered cross site scripting (since the JS file resides in another domain) so we need to be a bit more clever to make this work.  There is a way to load another JavaScript file and that’s to insert another “script” element in the “<head>” section in the html.  Once we do that, the browser will load the CKEditor JavaScript file for us to use.

var doc = parent.parent.document.getElementById("contentIFrame0").contentWindow.document;
var headblock = doc.getElementsByTagName('head')[0];
var newscriptblock = doc.createElement('script');
newscriptblock.type = 'text/javascript';
newscriptblock.src = '//';

Line by line, we first grab the ‘head’ element, but you’ll see the ‘parent.parent’ bit in there.  We need this because CRM puts the web resource inside an IFrame, and that IFrame is inside another IFrame as part of the content in the form.  So we use “parent.parent” to go up two levels, then get the main content IFrame so we can start adding elements there.  Next few lines we construct the script block we need, and last line we append that script block to the original head element.

At this point the browser will start loading the script file!  BUT, we have a catch, we can’t just write more JavaScript to start the replacement because we need to first wait for the CKEditor.js file to be loaded (and it’s dependencies).  So, we register an “onload” event before adding the script block that will do the actual replacements.  Like this:

newscriptblock.onload = function() {
    // We put our code here to get rich text

In my case, I have several text fields I want to replace, so instead of writing the code for each one separately, I created a string array with all the field names and will loop through.  We also need to do some tweaking on the page when the editor is loaded (hide the ‘value’ version of the field and show the ‘edit’ version of the field), we need to update the underlying field whenever the user types into the Rich Text Editor control, and wrap the whole thing in a function call (so we can call it from the form load method.  All in all the script came together nicely – you can see the full details below!

UPDATE [2/8/2016]:  I updated the code below to work with the latest Dynamics CRM Online, thanks to Anton Kurnitzky for his help!

UPDATE [4/17/2017]:  Code below updated again to work with forms & more dynamic UI, thanks to Brian Poff for his help! NOTE: In this version you have a few more places to update, search for “description”, your first field in the list should be updated in all the locations. Thanks!

function convertToRichText() {

    var CKIFrame = findCKEditorFieldIFrame("description");

    // import the ckeditor script, but do it without web resources..  so we create a script tag in the DOM
    var headblock = parent.parent.document.getElementById(CKIFrame).contentWindow.document.getElementsByTagName('head')[0];
    var newscriptblock = parent.parent.document.getElementById(CKIFrame).contentWindow.document.createElement('script');
    newscriptblock.type = 'text/javascript';
    // we have to wait until the script is loaded before we can use it, so registering a callback event
    newscriptblock.onload = function () {

        var CKIFrame = findCKEditorFieldIFrame("description");

        // some configuration for the CKEDITOR rich text control
        var CKE = parent.parent.document.getElementById(CKIFrame).contentWindow.CKEDITOR;
        CKE.config.allowedContent = true;
        CKE.config.toolbarCanCollapse = true;
        CKE.config.toolbarStartupExpanded = false;
        CKE.config.width = '95%';

        var fieldsToReplace = ["description", "detailedstatus"];
        for (var i = 0; i < fieldsToReplace.length; i++) { 
             var fieldname = fieldsToReplace[i]; 
             // We find the 'edit' control for the engagement overview and replace it with a rich text control 
             var richtexteditor = CKE.replace(fieldname + '_i'); 
             richtexteditor.on('instanceReady', function () { 
                parent.parent.document.getElementById(CKIFrame).contentWindow.document.querySelector('div#' + fieldname + ' >').style.display = "none";
                parent.parent.document.getElementById(CKIFrame).contentWindow.document.querySelector('div#' + fieldname + ' >').style.display = "inline-block";
                parent.parent.document.getElementById(CKIFrame).contentWindow.document.querySelector('div#' + fieldname + ' >').style.width = "95%";

                (function (field) {
                    richtexteditor.on('change', function (evt) {
                        // when the value in the rich text control changes, we update the underlying entity field + the 'view' version of the control
    newscriptblock.src = '//';

function findCKEditorFieldIFrame(fieldName) {

    var frameNum = 0;
    var doc = parent.parent.document;

    while (doc.getElementById("contentIFrame" + frameNum.toString()) != undefined) {
        if (doc.getElementById("contentIFrame" + frameNum.toString()).contentWindow.document.getElementById(fieldName) != undefined)
            return "contentIFrame" + frameNum.toString();

Now that we have the script, we copy/paste this into the “Text Editor” for the web resource we were creating above and click “Save” and close the Web Resource form, then click “Add” on the Look Up Record dialog box (assuming the web resource you just created is selected).  Next, on the “Form Properties” dialog under Event Handlers, we click “Add” to add the function call to the JavaScript we included above.


This part is the easy part, we just need a pointer to our function above!  We named our function convertToRichText, so I filled out the dialog like this:


Click OK, save the updated form and publish live – you should be good to go!  At this point, when the page loads the text field will be replaced by a rich text field, changes will get automatically applied to the underlying field and you’re all set.  I particularly like this approach (sitting inside the DOM with the rest of the elements instead of inside an IFrame) because you can resize the editor (grab the lower right and drag) to make the editor bigger and all the elements will fall in correctly around it, auto-magically!


Comments (8)

  1. sabir says:

    Hi ,
    This article to use the Rich text can u plz let me know why ur using the look up field in the code, I why we need to have the look up.\\


    1. Hi Sabir – are you talking about this?
      var fieldsToReplace = [“company_textmodulebackingfield”, “company_textmodule2backingfield”];

      The reason I used an array here was to enable replacing multiple fields with rich text boxes on the same page without needing to modify the code to do it.. Was that your question? If not, could you let me know which part of the code wasn’t clear? I’m happy to help!

  2. Vittorio Cicognani says:

    I’m sorry but I have the same error on line 22, ReferenceError: ‘convertToRichText’ is undefined at eval code.

    I take a look at the script with this debugger and it seems
    that this line is wrong
    for (var i = 0; i’).style.display = “none”;

    It seems a syntax error…can you tell me how to correct this?

    Thank you
    Vittorio Cicognani

    1. Hi Vittorio – yes, the code is incorrect now. I’m not exactly sure what happened, let me see if I can find the code and get this corrected… I’ll let you know as soon as it’s fixed!

      1. I was just able to fix the code, let me know if you have trouble!

  3. Dotch says:


    Thanks for your article, it’s very helpfull.
    I got a problem when I had several rich text on the same form.
    Indeed, only the last field to replace is working well.

    I have two field to replace “acc_description”, “acc_topline”, when I made a modification in the first field, the form doesn’t understand I made a change and the automatic saving is not triggered.
    The second one works correctly.
    Do you have an idea ?
    I didn’t made any changes on your code.
    Thanks for you help

    1. Hi Dotch – unfortunately I don’t have an environment anymore where I can debug the code to see if something isn’t working correctly… Feel free to send me an email to peter hauge microsoft com and we can work something out. Thanks!

  4. Hi Peter,

    I implemented the JS code exactly as you have it above and attached it to the Lead main form onFormLoad event. It works great to give the Description a little CK Editor for editing in rich text. Thanks!

    The reason I was looking for this is because I have set up an Email to Lead Creation using a Queue and Auto Create Record Rule, and the email message/body appears in the Lead Description field with all the HTML tags. Ideally I’d like to strip the HTML tags and just have plain text, although your method of displaying it as rich text is also appealing.

    For the specific scenario I am using this for, I noticed a couple of limitations and wondering if you have any thoughts on workaround or solution?

    1) I cannot save any changes in the CK Editor / Description field. Dynamics does not recognize it as a changed field when editing inside the CK Editor. When I click away from the CK Editor, it goes back to the previous version with all HTML tags and no changes are saved.

    2) All the HTML tags are still displayed in the field (fed from my email Description to Lead creation) until the user clicks inside the Description field, so I assume it is still storing all the HTML tags in the DB? If that’s the case, we would need to strip out the HTML tags for reporting. Is there a way to save it as text in the DB without the HTML tags?


Skip to main content