Quill rich text editor practice - DevUI

DevUI It is an open-source front-end solution for enterprise middle and back office products. It advocates the design values of immersion, flexibility and simplicity, advocates designers to serve the real needs and design for most people, and rejects the design that attracts the attention of the public. If you are developing tool products of ToB, DevUI will be a good choice!


The rich text editor is probably the most complex and widely used component.

It can be said that the rich text editor makes Web data entry full of infinite imagination. If there are only text only data entry components such as text box and drop-down box, the data entry ability of the Web will be greatly limited. We will not be able to insert rich text content such as pictures and videos on the Web page, let alone custom content.

Rich text editor makes Web content editing easier and more efficient. We can insert almost any content you want to insert in the rich text editor, including pictures, videos, hyperlinks, formulas and code blocks. We can even insert super complex custom content such as tables, ppts, mind maps and even 3D models.

The scene of rich text editor can be seen everywhere on the Web. Rich text is required for writing articles, comments, feedback and recording demand lists.

Combined with the practice of DevUI team in rich text components, this paper shares with you the things about Quill rich text editor, from the use scenario, technology selection, to the extension of Quill, and the basic principles of Quill.

This paper mainly consists of the following parts:

  1. Usage scenario of rich text editor
  2. Technology selection
  3. Why did we choose Quill
  4. How to extend Quill
  5. Quill Fundamentals

The following content comes from Kagol's speech at Huawei HWEB big front-end technology sharing meeting.

Usage scenario of rich text editor

  • Blog post
  • Wiki entries
  • Work item description
  • Test case steps
  • Feedback
  • comment
  • ...

Technology selection

Our needs:

  • Open source protocol friendly
  • Angular frame or frame independent
  • Flexible and scalable
  • Supports inserting / editing tables and pictures
  • Rich plug-ins and good ecology

Type selection analysis

  • First, exclude ueditors that are not maintained officially
  • Then exclude the draft.net exclusive to the React framework JS and Slate
  • Then exclude CKEditor, which is unfriendly to the open source protocol
  • Due to our rich business scenarios and the need for rich text insertion / editing table functions, we also need to exclude Trix that does not support tables, Etherpad and Prosemirror that weakly support tables, and TinyMCE that charges for table functions
  • Finally, only Quill and wangEditor are available. wangEditor is not as scalable and ecological as Quill, so Quill is finally selected as the base of rich text components

Why Quill?

  • BSD agreement, business friendly
  • The document is detailed and easy to use
  • API driven, good scalability
  • Rich plug-ins and good ecology

Document details

Document: https://quilljs.com/

Introduce Quill's API:

Describes how to extend Quill:

Get started

  • Install Quill: npm i quill
  • Import style: @ import 'quill / dist / quill snow. css';
  • Import Quill: import Quill from 'quill';
  • Initialize Quill: new Quill ('#editor', {theme: 'Snow'});

design sketch:

API driven, good scalability

Rich plug-ins and good ecology

Extend Quill

Insert label

For example, I want to insert labels in the editor

Upload attachments

For example, I want to insert an attachment in the editor

Insert expression

For example, I want to insert an expression in the editor

Similar comments: https://www.yuque.com/yuque/blog/sguhed

Personality segmentation line

For example, I want to insert the personalized dividing line of station B

Hyperlink card

For example, I want to insert a hyperlink card like Zhihu

How to insert expressions?

Let's start with how to insert expressions and see how to insert custom content in Quill.

To insert an expression in Quill, you only need the following four steps:

  • Step 1: Customize Toolbar Buttons
  • Step 2: customize the content of EmojiBlot
  • Step 3: register EmojiBlot in Quill
  • Step 4: call Quill's API to insert the expression

Step 1: Customize Toolbar Buttons

const quill = new Quill('#editor', {
  theme: 'snow',
  modules: {
    // Configure toolbar module
    toolbar: {
      container: [ ..., [ 'emoji' ] ], // Add a button
      handlers: {
        // Add button processing logic
        emoji() {
          console.log('Insert expression');

Add icons to toolbar buttons

// Extend Quill's built-in icons configuration
const icons = Quill.import('ui/icons');
icons.emoji = '<svg>...</svg>'; // The svg of the icon can be copied from the iconfont website

The effect is as follows:

There is already an emoticon button on the toolbar, which can respond to mouse click events. The next step is to write the specific logic of inserting emoticons, which involves Quill's knowledge of custom content.

Step 2: customize the content of EmojiBlot

The blog in Quill is an ordinary ES6 Class. The difference between expression and picture lies in:

Quill's built-in image format does not support custom width and height, and the expression we want to insert needs a specific width and height.

Therefore, we can extend it based on Quill's built-in image format.


import Quill from 'quill';

const ImageBlot = Quill.import('formats/image');

// Extend Quill's built-in image format
class EmojiBlot extends ImageBlot {
  static blotName = 'emoji'; // Define the name of the custom blog (must be globally unique)
  static tagName = 'img'; // Label name of custom content

  // Create a DOM node for custom content
  static create(value): any {
    const node = super.create(value);
    node.setAttribute('src', ImageBlot.sanitize(value.url));
    if (value.width !== undefined) {
      node.setAttribute('width', value.width);
    if (value.height !== undefined) {
      node.setAttribute('height', value.height);
    return node;
  // Return options data
  static value(node): any {
    return {
      url: node.getAttribute('src'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height')

export default EmojiBlot;

Step 3: register EmojiBlot in Quill

With EmojiBlot, to insert it into Quill editor, you also need to register this ES6 class in Quill.

import EmojiBlot from './formats/emoji';
Quill.register('formats/emoji', EmojiBlot);

Step 4: call Quill's API to insert the expression

After EmojiBlot is registered in Quill, Quill can recognize it and call Quill's API to insert it into the editor.

emoji(): void {
  console.log('Insert expression');
  // Gets the current cursor position
  const index = this.quill.getSelection().index;
  // Insert emoji (blotName) at the current cursor
  this.quill.insertEmbed(index, 'emoji', {
    url: 'assets/emoji/good.png',
    width: '64px',

design sketch

Demo source code

Source code link: https://gitee.com/kagol/quill-demo

Also welcome to follow the official website of our DevUI component library to learn more interesting and practical open source components!

DevUI official website: https://devui.design

Quill Fundamentals

Finally, let's talk about the basic principle of Quill.

Basic principles

  • Delta data model is used to describe the rich text content and its changes to ensure the predictability of behavior
  • DOM is abstracted through parsment to ensure platform consistency
  • Monitor the changes of DOM nodes through rotation observe and synchronize the changes of DOM to the Delta data model

How does Quill express editor content?

Delta data model

Delta data model is used to describe the rich text content and its changes

Delta is a subset of JSON and contains only one ops attribute. Its value is an array of objects. Each array item represents an operation on the editor (based on the empty initial state of the editor).

  "ops": [
    { "insert": "Hello " },
    { "insert": "World", "attributes": { "bold": true } },
    { "insert": "\n" }

Modify editor content

For example, we change the bold "World" to the red text "World". This action is described as follows with Delta:

  "ops": [
    { "retain": 6 },
    { "retain": 5, "attributes": { "color": "#ff0000" } }

It means: keep the first 6 characters of the editor, that is, keep "Hello" and the next 5 characters "World", and set these characters to the font color of "#ff0000".

Delete editor content

What if you want to delete "World"?

  "ops": [
    { "retain": 6 },
    { "delete": 5 }

That is: keep the first 6 characters ('Hello ') and delete the next 5 characters ('World')

How does Quill render content?

The basic principle of rendering rich text content: traverse the Delta array and apply (insert / format / delete) the content described in it to the editor one by one.

For details, please refer to DevUI column:

Quill's content rendering mechanism

How does Quill extend the capabilities of the editor?

How to extend Quill:

  • Expand the content of the editor by customizing the format of blog
  • Extend the functions of the editor by customizing the module

For details, please refer to DevUI column:

Modular mechanism of Quill, a modern rich text editor


Keywords: Front-end angular TypeScript

Added by broomstick on Tue, 08 Feb 2022 06:36:00 +0200