3 horizontal lines, burger
3 horizontal lines, burger
3 horizontal lines, burger
3 horizontal lines, burger

3 horizontal lines, burger
Remove all
LOADING ...

Content



    How to make custom QuillJS module – table of content as an example

    Clock
    29.10.2024
    /
    Clock
    02.10.2025
    /
    Clock
    4 minutes
    An eye
    1747
    Hearts
    0
    Connected dots
    0
    Connected dots
    4
    Connected dots
    0

    Introduction

    In this article, I will explain how to create and add your own quill module. We will do all this by creating such a useful module as a table of contents generator for an article.
    There is already something similar on the official website for quill, but it does not cover all the problems that I encountered when creating this module. For example, how to disable the module. I did not find this in the official documentation. And the organization of connecting the module, frankly speaking, also cannot be the same as it was shown. But anyway, a very interesting and informative article. ☜(゚ヮ゚☜) Check this out.

    Registrating a module and making for him a switcher

    Let me start with how we connect (or register) this module. To do this, we will assign the value "modules/table_of_contents" to the first variable, and the second variable will be the name of the initializing function. Like this:
    Quill.register('modules/table_of_contents', InitTableOfContents);
    Now to the implementation of the initialization function itself. In order for the table of contents to be generated dynamically, we will connect a function to quill. Which will be called every time the text changes.
    function InitTableOfContents(quill, options) { quill.on(Quill.events.TEXT_CHANGE, RunTableOfContents); }
    Let's connect our custom module to the editor.
    const quill = new Quill('#editor', { modules: { table_of_contents: true, toolbar: { container: '#toolbar-container', } }, placeholder: '', theme: 'snow', });
    Okay, we connected it, but how to disconnect it? (⊙_⊙)?Simply put, it's not possible. At least I didn't figure out how. Or rather, I figured it out, but I'm not sure if this is the right method. Quill has getModule and addModule methods, but it doesn't have deleteModule or removeModule. Which is certainly strange.
    As an option for deleting a module, you can use delete on an associative array (where, in fact, all the modules are contained). And this won't work. After all, we also add our own handler for the text change event. And when deleting a module, the handler will remain ¯\(°_o)/¯
    Therefore, my solution to this issue is not deleting the module but deleting the event handler itself. In my case, it is RunTableOfContents. On the HTML editor page, you can find a checkbox for enabling and disabling this module. (As you already understood, it does not delete the module but the RunTableOfContents handler.)
    Below I will present the code of the handler itself. What is my point? All handlers are stored in the _events variable of emmiter. To add and/or remove a handler, use the addListener (and removeListener) method(s), which accept 3 (4) arguments:
    1. Handler type (for me it is TEXT_CHANGE)
    2. Function name
    3. Context (Always pass quill.emmiter)
    4. A boolean value that is used to run the passed function once.
    document.querySelector('#toc_module').addEventListener('click', (event)=>{   if (event.target.checked){     quill.emitter.addListener(Quill.events.TEXT_CHANGE, RunTableOfContents, quill.emitter)   }else{     quill.emitter.removeListener(Quill.events.TEXT_CHANGE, RunTableOfContents, quill.emitter, false)   } })
    We are done with connecting and configuring the switcher. Let's take a look at the implementation.

    How table of contents are generated and implemented

    I want to clarify right away that I did not add the H1 tag because I was primarily creating the tool for myself. And this tag does not participate in the generation of the table of contents. You, in turn, are free to change, rotate, and disassemble the code into anything. No one will stop you (~ ̄▽ ̄)~.
    Here is the code for the RunTableOfContents handler.
    function RunTableOfContents(){ let range = quill.getSelection() let blot = Quill.find(quill.getLeaf(range.index)[0].domNode).parent let DOMnode = blot.domNode switch (DOMnode.tagName){ case 'H2': case 'H3': case 'H4': case 'H5': case 'H6': document.querySelectorAll('.table_of_contents').forEach((el) => { let prev = quill.scroll.find(el) if (prev){ prev.remove() } }) var container = quill.scroll.create(TableOfContents.blotName) var ref = quill.scroll.children.head quill.scroll.insertBefore(container, ref) break } }
    This handler finds the blot where the cursor is currently located and checks its type by tag. If the cursor is on the table of contents tags, i.e. from h2 to h6, it updates the table of contents after deleting the previous one.
    For the table of contents, I use a custom formatter. Here's how I implemented and registered it.
    class TableOfContents extends Quill.import('blots/block'){ static create(value){ let node = super.create(value); return node } constructor(scroll, domNode){ super(scroll, domNode) var header = document.createElement('h2') header.innerText = document.querySelector('#table_of_content_text').innerText header.style.marginTop = '0' header.style.borderBottom = '2px solid gray' header.style.marginBottom = '0' domNode.insertAdjacentElement('beforeend', header) document.querySelectorAll('h2,h3,h4,h5,h6').forEach( (heading) => { if (!heading.classList.contains('table_of_contents')){ var container_headers_element = document.createElement('div') let tag_name = heading.nodeName.toLowerCase() let padding = "padder-5" if( tag_name == 'h2') padding = "padder-5" else if (tag_name == 'h3') padding = "padder-10" else if (tag_name == 'h4') padding = "padder-15" else if (tag_name == 'h5') padding = "padder-20" else if (tag_name == 'h6') padding = "padder-25" container_headers_element.classList.add(padding) container_headers_element.style.display = 'flex' container_headers_element.style.gap = '8px' container_headers_element.style.alignItems = 'center' container_headers_element.style.marginTop = '10px' var container_headers_sign = document.createElement('p') container_headers_sign.innerText = tag_name container_headers_sign.style.border = '1px solid grey' container_headers_sign.style.borderRadius = '50%' container_headers_sign.style.padding = '5px' container_headers_sign.style.color = 'grey' container_headers_sign.style.fontSize = '10px' var container_headers_text = document.createElement('p') container_headers_text.innerText = heading.innerText container_headers_element.insertAdjacentElement('beforeend', container_headers_sign) container_headers_element.insertAdjacentElement('beforeend', container_headers_text) this.domNode.insertAdjacentElement('beforeend', container_headers_element) } }) } } TableOfContents.tagName = 'div' TableOfContents.blotName = 'table_of_contents' TableOfContents.className = 'table_of_contents' Quill.register({'formats/table_of_contents': TableOfContents})
    At some point, I wanted to implement it as a container (that is, to extend it from blots/container). But I thought this was too much for this module, and it is not worth complicating it further.
    And one more thing. I could use CSS selectors for styling, but I thought that it would probably be easier for the reader to perceive this form without the need to take into account cascading styles.

    Conclusions and other notes

    In fact, for the correct operation of this module, it is necessary to perform additional cleaning of the editor. Since my custom formatter is not fully implemented. I perform cleaning in the loadQuill function. Immediately after I have loaded the content onto the page.
    function loadQuill( content ){ var scope = document.querySelector('.ql-editor') scope.innerHTML = content var table_of_content = scope.querySelector('.table_of_contents') if (table_of_content){ table_of_content.remove() } }
    Also, I didn't make the table of contents dynamic, that is, I didn't add internal links to the corresponding headings. Sorry, I was too lazy. (ಥ _ ಥ)
    And so, the functionality of this module can be found on the page of my rich quill editor. Also, if you suddenly didn't notice, at the very beginning of this article there is a corresponding block with a table of contents. Take a look, admire it (⓿_⓿)

    Do not forget to share, like and leave a comment :)

    Comments

    (2)

    captcha
    Send
    LOADING ...
    Часы
    May 15, 2025, 4:43 p.m.
    Человек
    kjkjkjk
    jgjkhjk
    All replies (1)
    Reply
    LOADING ...
    Часы
    April 25, 2025, 10:41 a.m.
    Человек
    kjkjkj
    jjhjk
    All replies (1)
    Reply
    LOADING ...

    Other

    Similar articles


    All about quill blots, blocks and how to make a custom blot

    Clock
    24.10.2024
    /
    Clock
    02.10.2025
    An eye
    4814
    Hearts
    0
    Connected dots
    0
    Connected dots
    0
    Connected dots
    0
    In this article, I will tell you about kinds of quill blots and quill blocks, their differencies, how they are used (including an examples of realisation those blots, blocks). Also, …

    Quill formats(ql-formats), How to make custom format

    Clock
    24.10.2024
    /
    Clock
    02.10.2025
    An eye
    3885
    Hearts
    0
    Connected dots
    1
    Connected dots
    0
    Connected dots
    0
    In this article, I will analyze the types of quilljs formats and explain some of the nuances of working with tables, fonts, images, and video. I will also show how …

    Quill tooltip, how to make your own. Example on links

    Clock
    25.10.2024
    /
    Clock
    02.10.2025
    An eye
    2277
    Hearts
    0
    Connected dots
    0
    Connected dots
    0
    Connected dots
    0
    In this article, you will find an example of how to implement your own Quill tooltip. And you will get how this even works. As an example, a tooltip will …

    Custom toolbar button, how to make for quill editor

    Clock
    25.10.2024
    /
    Clock
    02.10.2025
    An eye
    3351
    Hearts
    0
    Connected dots
    0
    Connected dots
    0
    Connected dots
    0
    In this article I will show you how to create custom buttons for your quill editor. You will also learn how to add a drop-down list for the same quill …

    Used termins


    Related questions