How to enable Rich Text in Dynamics CRM using CKEditor

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').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 (34)

  1. Scott Clancy says:

    Nice job Peter this is very cool!

  2. Mike Adler says:

    Great post Peter.  I got it working but I want to add the ability to pick the text color. Is there a way to add the CKEditor plugins with your method?

  3. Sure!  Shouldn't be too hard to add color (in fact, I should do that in mine too. 🙂 ).  It looks like the Color plugin is available in the 'full' distribution of CKEditor –…/colorbutton.html .  So you should swap this line:

               newscriptblock.src = '//';

    with this one:

               newscriptblock.src = '//';

    An alternative method, if you hosted your own version of the CKEditor package somewhere (with only the add-ins you wanted), you would just change the URL to your hosted location.  That way you would only have the plugins you are planning on using.

  4. Mike Adler says:

    Changing the URL for the editor worked great. I now see the full editor with text color. I have another issue now. When I type in the editor it is not updating the underlying field. So the CRM doesn't think the record is dirty and does not save my changes. Any advice on that one?

  5. Hi Mike – I bet there's something different on your CRM site than mine on how the fields are named.  The code above uses the XRM object model to set the underlying field (which fires the 'change' events that trigger save).

              richtexteditor.on( 'change', function ( field ) {

                  // when the value in the rich text control changes, we update the underlying entity field + the 'view' version of the control



    The best way to figure out what's going on is using the browser debugging tools on the site (F12 for Internet Explorer).  You can load the page, search for this line of code in javascript and set a breakpoint.  Type something in the editor and then make sure that returns the correct field (and isn't null)…  My guess is that the field name doesn't match up.  For example, the JQuery selectors will find the field regardless of capitalization, but I think this XRM call is sensitive to correct capitalization of the field.

    Hope that helps, if not let me know!

  6. Patrick Sengeis says:

    Hey Peter,

    thanks for the interresting article. I see the CKEditor in the form, but unfortunately it doesn't save the content. I noticed that everytime I press a key in the editor, I get an "Uncaught TypeError: Cannot read property 'call' of undefined". The error is thrown from ckeditor.js. Currently I'm working with Microsoft Dynamics® CRM 2016. Have you tried the CKEditor with the new CRM already? Or do you have any ideas how to make it working?

    Best regards!

  7. Hi Patrick – good question, I haven't tried this on Dynamics CRM 2016 yet, we are upgrading probably in Jan sometime…  I bet it's because the page is structured slightly different.  I'm happy to help further, but we should probably take the conversation out of blog comments – you can email me directly at peter dot hauge at microsoft dot com if you want to dig further. 🙂  Thanks!

  8. Good news – I just got this working on the latest Dynamics CRM online!  I updated the code above, thanks to Anton Kurnitzky for his help!

  9. Sumeet says:

    Hello Peter,

    Thanks a lot for this!! We were able to get ckeditor working in our crm form using your guidance…

    We have just one issue now…the CRM field shows the HTML markup text…and not the rich text editing when form loads…

    Only when we click on the field…does the Ckeditor showup…any suggestions on how to get around this?

  10. Great – really glad it was helpful!  My best guess is that the script block is loading faster than the other UI elements on the page, but probably can't really diagnose without seeing it.  Feel free to reach out directly (my email is in one of the prior comments) and we can work through it.

    1. Maria says:

      Hi Peter,

      Excellent page! I’d been using the CKEditor via an html webresource previously, but after an upgrade to CRM 2016, this no longer worked. Your tips worked like a charm and was much easier to set up! If only this page had been available when I set it up in the first place 😉

      I have a similar issue as Sumeet – if focus is on any other field than the description field, it reverts to showing the HTML markup text instead of the rich text editor. It’s no big deal, as the editor returns once focus returns to the field, I was just wondering if you might have any ideas as to what is happening?

      Thanks for a great post 🙂

      1. Hi Maria – sorry for the late reply, for some reason your comment wasn’t auto-published but went to the junk spot, I just found it there! This probably has something to do with how the script is setup on the page. I’m happy to help diagnose/debug – feel free to contact me directly at peter dot hauge at microsoft dot com. 🙂

  11. Jake Clauson says:

    This method uses document.getElementById(), rendering it unsupported. Do you have a recommended way of implementing the CKEditor in a supported fashion?

    1. Jake Clauson says:

      Just clarifying that the use of document.getElementById() on its own is not unsupported, but using it to manipulate the form is.

      1. Hi Jake – sorry for the delay responding, your comment ended up in the junk area instead of being auto-published, not sure why! I don’t have a recommendation since the overall approach here is manipulating the DOM which is generally not supported. I found it works well, but it isn’t officially supported.

  12. Idalette de Bruin says:

    Thank you so much for this post it has been extremely useful, and I can see the editor when I load my form. I then tried to change to the full version and when I went into the form again the web resource was not there, but if I go to Web Resources entity it is there. I altered it in the Web Resources entity and published but it has not updated the form. Can you giveme any idea why this would be?

    Many thanks

  13. Idalette de Bruin says:

    I have followed the step above and I have received the following error convertToRichText is undefined at eval code {eval code 1:1)

    Any guidance would be greatly appreciated

    The log file shows this

    ReferenceError: ‘ConvertToRichText’ is undefined
    at eval code (eval code:1:1)
    at RunHandlerInternal (
    at RunHandlers (
    at Anonymous function (
    at Anonymous function (

    1. Idalette de Bruin says:

      Using CRM online 2016 fresh installation. I have tried to set the legacy from rendering option, but this has not solved the error

    2. Idalette de Bruin says:

      Seems to have an error
      SCRIPT1014: Invalid character
      new_ReplaceMyFieldsWithRichText.js (16,47)

    3. Hi Idalette, I saw you sent me email directly, thanks! Just post back here with the solution once we figure it out. 🙂

      1. Neil Benson says:

        I’m getting the same error message as Idalette. Let me know if you find a resolution. (I’m using CRM Online 2016 Update 1 with Project Services Automation).

        1. Hi Neil – Idalette decided to go another route (use another browser for clickable links)… I can help debug, could you drop me an email and we can go from there? peter dot hauge at Microsoft dot com. Thanks!

  14. Nick says:

    This looks promising, but I am getting a “Unable to get property ‘getEditor’ of undefined or null reference” error and the editor controls don’t show up… any ideas? This is for CRM 2013 on-premise.

    1. Hi Nick – I’ve seen that error before when JQuery wasn’t loaded properly, or the CKEditor wasn’t initialized. Feel free to connect with me at peter dot hauge at Microsoft dot com and we can go through it together. Thanks!

  15. Timothy Halse says:

    You solution is good however i have found a few problems with CRM 2016 Online.
    On the initial load of the form the script doesn’t work correctly as the ckeditor javascript hasnt fully loaded yet so you get a TypeError: Cannot call method ‘getEditor’ of undefined. However once you reload the form it works as intented.

    Another problem i have found with your script is that when using multiple fields it doesn’t work as expected. I have trying doing this with 3 fields however it only works on the last field in the array, also the other 2 fields won’t save and only show the Rich Text Editor when you focus on them.

    I have developed the script to be working with multiple fields however i can seem to fix the problem of loading the form for the first time.

    We can communicate if you would like to come up with a solution.

    1. Hi Timothy – thanks for checking this out! I got your mail and replied… Let us know if the updated code works, if so I can update the blog post directly with the info. Thanks!

      1. Ajitav says:

        Hello Peter,
        First of all thank you so much for this blog . We are also facing the same issue ,the ckeditor instances are not loading on the initial load but once we refresh the CRM form the CKeditor instances are loading fine . Please help us with the updated code.
        Note : This was working fine when turbo was not enabled . Once we enabled turbo forms we are facing this issue .

        1. Just updated the code in the post – let me know if you have any trouble!

          1. Ajitav says:

            Wow !!. This worked like a charm .Thank you so much Sir !!

          2. Timothy Halse says:

            Hello Peter, I am just checking your code again in this blog and it seems to be incorrect.
            You may need to update it with your latest code.
            I have also ran into another issue where if someone click on the expand or source toolbar button in ck editor and then saves the form in a https environment the field reverts back to a normal field until you enter the field again in which it will then go back to a CK Editor field

  16. Marie says:

    Hi Peter,
    This is a very handy solution. Can it be utilized anyhow for Notes editor? I cannot find any way to access notes editor.

    1. Hi Marie – I haven’t tried with the notes editor unfortunately. As far as I’ve gone with my experimenting it works with any fields that are stored as plain text in CRM. If you want to look into this together just send me some email (check the other comments for my email address) and we can look into it. Thanks!

  17. trur says:

    Hi Peter,

    just wanted to let you that the source seems to be messed up a bit (looks like a copy&paste accident), see line 22 e.g.
    Thanks for the great work.

    1. Thanks for letting me know! I’ll check this out and fix soon, thanks!

Skip to main content