Skip to content

Custom blot format in Quill not translating to HTML

I am setting up Quill to use as a rich text editor in a blog project. I have the editor working correctly and can store user posts in mongoDB, retrieve them later, and display them.

My code for doing this involves grabbing the delta from quill, stringifying it, then encoding this as a URI. This is what is stored in my db. These actions take place upon hitting my post button but before submitting the form. I am also storing the plain text for other purposes.

function parseQuill(){
document.getElementById("body").value = encodeURIComponent(JSON.stringify(quill.getContents()));
document.getElementById("bodyText").value = quill.getText();


When accessing a blog post, the delta is retrieved from the db and converted back into html for viewing. This takes place on the backend. The decoded HTML is sent to my post page and rendered with ejs.

app.get("/posts/:postID", function(req, res){
User.findOne({name: "user1"}, function(err, foundUser){
let posts = foundUser.posts;
if (post._id == req.params.postID){
    const decoded = JSON.parse(decodeURIComponent(post.content));
    const converter = new QuillDeltaToHtmlConverter(decoded.ops);
    const decodedHTML = converter.convert();
    post.decoded_HTML = decodedHTML;
    res.render("post", {post: post});

This works for all of the default formats that quill offers.

I have been following along with the Quill guide “Cloning medium with parchment” and have attempted to implement the custom divider blot. My code is identical to what is happening there minus the jQuery. My horizontal rule appears in the text editor and behaves as expected.

My issue arises when saving the delta and attempting to convert it back to html. The delta.ops for a post with a horizontal rule looks something like this.

 {"insert":"Some text followed by a horizontal rule.n"},
 {"insert":"Some more text.n"}]}"

The line representing the horizontal rule is the second insert statement of “divider”: true. After storing this as a URI component and decoding it back to HTML, the HTML looks like this:

<p>Some text followed by a horizontal rule.<br/>Some more text.</p>

The horizontal rule tag is nowhere to be found. How can I get this to be interpreted correctly and show up?

If I produce a hidden Quill editor container on my post page, I can load in the pure delta and extract the html with quill.root.innerHTML. This produces HTML that contains the HR. I was hoping to avoid inserting the hidden quill container, if at all possible.



I was an idiot and missed an important step in the html decoding process. Leaving this question up with this answer (which solves the problem) incase anyone else stumbles upon a moment of mental ineptitude.

I was using the package quill-delta-to-html to convert my delta’s back to usable html. Of course this package doesn’t know how to register custom blots. You have to do that manually before converting.

const dividerOp = {
      insert: {
        type: "divider",
        value: true
      attributes: {
        renderAsBlock: true
      if (dividerOp.insert.type === "divider"){
        return "<hr>"
      } else {
        console.log("custom blot convert error");
    const decodedHTML = converter.convert();

Quill was doing everything right on it’s end. I had a lapse in memory and forgot I was relying on an external package to handle my delta to html conversions. Adding this customBlot render solves the issue.