Use Quill as a Rich Text Editor in ASP.NET Core

09/19/2019

Use Quill as a Rich Text Editor in ASP.NET Core

Use an existing open-source rich text editor in your ASP.NET Core web applications.

Recently we ran into an issue where our preferred commercial UI components would not work with our preferred UI framework, which for this particular project happened to be Bulma. Specifically, our commercial components only offer Bootstrap or Material for UI support, and when we tried to use either options with our Bulma framework, things would get...not quite 'ugly', but some features did not play well together - at least not with the rich text editor which we really like.

So while looking for a new rich text editor for our project, we encountered Quill, an open-source rich text editor written in Javascript that, unlike TinyMCE or other 'free' components out there, doesn't try to tie you in to any cloud platform or come with other odd strings attached.

Setting up Quill in our project took a little research, but we've managed to put together some fast and easy instructions which we thought would be worth posting.

First, we add in the CDN references at the top of our page:

<script src="//cdn.quilljs.com/1.3.6/quill.min.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">

Then we wire up our <form> tag like so:

<form id="form" asp-controller="OurController" asp-action="SaveData" onsubmit="handleSubmit()">

In our web form, we set up two fields: the first one will be our 'hidden' field for binding back to our ASP.NET model object, and the second field is for our rich text editor, like this:

<input type="hidden" id="jdr" asp-for="@Model.description"/>
<div id="description">
    @Html.Raw(Model.description)
</div>

The whole point of having a rich text editor is to generate 'rich text' i.e. HTML, so we want to make sure that when we go to display it, we're displaying what we're pulling out of our data source. In our data storage we convert this to/from Markdown, but when it comes to our display we're posting HTML - hence the @Html.Raw statement.

Finally, at the bottom of our page, we have some Javascript that binds everything together:

<script>
    let jdQuill = new Quill('#description', {
        theme: 'snow'
      });
    function handleSubmit(){
        console.info('handleSubmit called');
        document.getElementById('jdr').value = jdQuill.root.innerHTML;
    };
</script>

In our case, we have several editor instances, so we set up a more 'permanent' function for the form submit. It also took some research to find out that the quill.root.innerHTML value was what will actually give you the value of the rich text editor - it would be nice if the Quill documentation actually said anything about that, instead of finding it on Stack Overflow.

When that doesn't work

In some circumstances, you won't find any inner HTML. When this happens, you'll have to extract the editor contents by using the getContents() method.

Let's modify our method above to reflect this:

<script>
  function handleSubmit(){
      console.info('handleSubmit called');
      console.info('quill contents: ' + JSON.stringify(jdQuill.getContents()));
      document.getElementById('jdr').value = JSON.stringify(jdQuill.getContents());
  }
      </script>

When using this command, you're going to get a JSON document containing Quill's Delta format, which creates a sequence of JSON objects containing the content with some metadata around the formats used in the editor contents.

For example - when we create some content that looks like this:

Quill editor in ASP.NET Core

We get JSON output that looks like this:

  {"ops":[
  {"insert":"Here is the first paragraph.\n\nList item 1"},
  {"attributes":{"list":"bullet"},"insert":"\n"},
  {"insert":"List item 2"},{"attributes":
  {"list":"bullet"},"insert":"\n"},
  {"insert":"Here's another paragraph, and now an image:\n"},
  {"insert":{"image":"data:image/png;base64,iVBORw0KG..."}},
  {"insert":"\n"}
]}

Notice too that the binary contents of the (rather large) image we added in the editor was embedded directly into the message.

Fortunately, we have some tools to help us make sense of this data format. Using blushingpenguin's Quill.Delta, we can turn the Delta data into HTML, and set up a custom BeforeRender where we can modify the <img> objects to load image contents into Cloudinary where we can manipulate and manage them better.

One word of caution - some copy/paste functions copy all the style from the source, which can mess up your HTML. The Quill.Delta package will process that into your HTML output, so be mindful of where your sources come from!

Looking for help building or modernizing your web applications in the cloud? Contact us for a quote - not only is it free, but we can help you find what you're looking for at a better price than most consulting firms!