<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adam Charron</title>
    <description>The latest articles on DEV Community by Adam Charron (@charrondev).</description>
    <link>https://dev.to/charrondev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F22596%2Fc23142ef-976c-4763-a3a2-6ce88dc75fee.jpeg</url>
      <title>DEV Community: Adam Charron</title>
      <link>https://dev.to/charrondev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/charrondev"/>
    <language>en</language>
    <item>
      <title>Getting to know QuillJS - Part 1 (Parchment, Blots, and Lifecycle)</title>
      <dc:creator>Adam Charron</dc:creator>
      <pubDate>Wed, 14 Mar 2018 05:55:22 +0000</pubDate>
      <link>https://dev.to/charrondev/getting-to-know-quilljs---part-1-parchment-blots-and-lifecycle--3e76</link>
      <guid>https://dev.to/charrondev/getting-to-know-quilljs---part-1-parchment-blots-and-lifecycle--3e76</guid>
      <description>&lt;p&gt;This is the first of series of Blog posts on QuillJS and its data library Parchment. The following followup articles are planned and will be linked here when complete.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/charrondev/getting-to-know-quilljs---part-1-parchment-blots-and-lifecycle--3e76"&gt;Parchment, Blots, and Lifecycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Containers - Creating a Mutliline Block&lt;/li&gt;
&lt;li&gt;Inline Embeds - Creating an @mention Blot&lt;/li&gt;
&lt;li&gt;Block Embeds - Creating a Custom Video Blot without an iFrame&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: This series is targeted at people trying to gain an advanced understanding of Quill and Parchment. If you're just trying to get started with an easy, well-featured editor, it might be good idea to check out Quill's &lt;a href="https://quilljs.com/docs/quickstart/"&gt;Quickstart Guide&lt;/a&gt; or &lt;a href="https://quilljs.com/guides/cloning-medium-with-parchment/"&gt;Cloning Medium with Parchment guide&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Quill?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://quilljs.com/"&gt;QuillJS&lt;/a&gt; is a modern rich text editor built for compatibility and extensibility. It was created by &lt;a href="https://twitter.com/jhchen"&gt;Jason Chen&lt;/a&gt; and &lt;a href="https://twitter.com/byronmilligan"&gt;Byron Milligan&lt;/a&gt; and open sourced by Salesforce. Since then it has been used by hundreds of other companies and people to build fast, reliable, and rich editing experiences in a browser.&lt;/p&gt;

&lt;p&gt;Quill is a mostly batteries-included library with support for most common formatting options such &lt;strong&gt;bold&lt;/strong&gt;, &lt;em&gt;italics&lt;/em&gt;, &lt;del&gt;strike&lt;/del&gt;, underline, custom fonts and colors, dividers, headings, &lt;code&gt;inline code&lt;/code&gt;, code blocks, blockquotes, lists (bulleted, numbered, checkboxes), formulas, images, as well as embedded videos. &lt;/p&gt;

&lt;h2&gt;
  
  
  What more could you want?
&lt;/h2&gt;

&lt;p&gt;A few months ago, the company I work for, &lt;a href="https://github.com/vanilla"&gt;Vanilla Forums&lt;/a&gt; began planning a new editor for our product. Our current editor supported numerous different text entry formats, including&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markdown&lt;/li&gt;
&lt;li&gt;BBCode&lt;/li&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;WYSIWYG HTML (using an iFrame to render the contents)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We had different parsers, renderers, and frontend javascript for all of these formats, so we set out to create new editor to replace them all with a single new unified, rich editing experience.&lt;/p&gt;

&lt;p&gt;We chose Quill as the base of our new editor due to its browser compatibility and extensibility, but quickly realized that it was not going to have all of the functionality we needed out of the box. Notably lacking was multiline block type structures like block-quotes (missing nesting and multiline support). We have some other formatting items such as Spoilers with similar requirements.&lt;/p&gt;

&lt;p&gt;We also had some extended functionality to add in the form of rich link embeds, and special formatting options and functionality for images and videos.&lt;/p&gt;

&lt;p&gt;So I set to out to learn &lt;a href="https://github.com/quilljs/quill"&gt;Quill&lt;/a&gt; and its underlying data library &lt;a href="https://github.com/quilljs/parchment"&gt;Parchment&lt;/a&gt; inside and out. This series of posts represents my understanding of Parchment and QuillJS. I am not a maintainer of the project, so if something is incorrect here, I encourage you to point it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Formats
&lt;/h2&gt;

&lt;p&gt;Quill has 2 forms of data-formats. &lt;a href="https://github.com/quilljs/parchment"&gt;Parchment&lt;/a&gt; (Blots), and &lt;a href="https://github.com/quilljs/delta"&gt;Delta&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Parchment is used as an in-memory data structure made up primarily of LinkedLists in a tree structure. Its tree of Blots should map 1:1 with the browser's tree of DOM Nodes.&lt;/p&gt;

&lt;p&gt;Deltas are used to store persistant data from the editor and takes the form of a relatively flat JSON array. Each item in the array represents an operation, that could affect or represent multiple DOM Nodes or Blots. This is the form of data that you will generally store in your Database or persistent storage. It is also used to represent diffence between one state and another.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Blot?
&lt;/h2&gt;

&lt;p&gt;Blots are the building blocks of a Parchment document. They are one of the most powerful abstractions of Quill, as they allow the editor and API users to consume and modify the document's contents without needing to touch the DOM directly. Blots have a simpler and more expressive interface than a DOM Node which can make consuming and creating them easier to reason about.&lt;/p&gt;

&lt;p&gt;Each Blot must implement the interface &lt;code&gt;Blot&lt;/code&gt; and every existing Blot in Quill and Parchment is a class that inherits from &lt;code&gt;ShadowBlot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to make it possible to look around the document from the perspective of a Blot, every Blot has the following references&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.parent&lt;/code&gt; - The Blot that contains this Blot. If this Blot is the top level Blot, &lt;code&gt;parent&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.prev&lt;/code&gt; - The previous sibling Blot in the tree from this Blot's parent. If this iBlotis the first child directly under its &lt;code&gt;parent&lt;/code&gt;, &lt;code&gt;prev&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.next&lt;/code&gt; - The next sibling Blot in the tree form this Blot's parent. If this Blot is the last child directly under its &lt;code&gt;parent&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.scroll&lt;/code&gt; - The scroll is the top level Blot in Parchment's data structure. More info about the Scroll Blot will be provided later.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.domNode&lt;/code&gt; - Since Parchment's tree maps 1:1 with the DOM's tree, each Blot has access to the &lt;code&gt;Node&lt;/code&gt; it represents. Additionally these DOM Nodes will have a reference to their Blot (with &lt;code&gt;.__blot&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Blot Lifecycle
&lt;/h2&gt;

&lt;p&gt;Each Blot has several “lifecycle methods” that you can override to run code at particular times in the process. You generally will still want to call &lt;code&gt;super.&amp;lt;OVERRIDEN_METHOD&amp;gt;&lt;/code&gt; before or after inserting your own custom code though. This component lifecycle is broken up into multiple sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creation
&lt;/h3&gt;

&lt;p&gt;There are multiple steps in properly creating a Blot, but these can all be replaced with calling &lt;code&gt;Parchment.create()&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Blot.create()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Each Blot has a &lt;code&gt;static create()&lt;/code&gt; function that creates a DOM Node from an initial value. This is also good place to set initial values on a DOM Node that are unrelated to the actual Blot instance.&lt;/p&gt;

&lt;p&gt;The returned DOM Node is not actually attached anywhere, and the Blot is still not yet created. This is because Blots are created &lt;em&gt;from&lt;/em&gt; a DOM Node, so this function puts one together in case there isn't already one. Blots are not necesarilly always constructed with their create function. For example, when a user copy/pastes text (either from Quill or from another source) the copied HTML structure is passed to &lt;code&gt;Parchment.create()&lt;/code&gt;. Parchment will skip calling create() and use the passed DOM Node, skipping to the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Block&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quill/blots/block&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ClickableSpan&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ClickableSpan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Allow the parent create function to give us a DOM Node&lt;/span&gt;
        &lt;span class="c1"&gt;// The DOM Node will be based on the provided tagName and className.&lt;/span&gt;
        &lt;span class="c1"&gt;// E.G. the Node is currently &amp;lt;code class="ClickableSpan"&amp;gt;{initialValue}&amp;lt;/code&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Set an attribute on the DOM Node.&lt;/span&gt;
        &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spellcheck&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Add an additional class&lt;/span&gt;
        &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;otherClass&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Returning &amp;lt;code class="ClickableSpan otherClass"&amp;gt;{initialValue}&amp;lt;/code&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;constructor(domNode)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Takes a DOM Node (often made in the &lt;code&gt;static create()&lt;/code&gt; function, but not always) and creates a Blot from it.&lt;/p&gt;

&lt;p&gt;This is the place to instantiate anything you might want to keep a reference to inside of a Blot. This is a good place to register an event listener or do anything you might normally do in a class constructor.&lt;/p&gt;

&lt;p&gt;After the constructor is called, our Blot is still not in the DOM tree or in our Parchment document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ClickableSpan&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Bind our click handler to the class.&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;clickHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ClickableSpan was clicked. Blot: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Registration
&lt;/h3&gt;

&lt;p&gt;Parchment keeps a registry of all of your Blots to simplify creation of them. Using this registry, Parchment exposes a function &lt;code&gt;Parchment.create()&lt;/code&gt; which can create a Blot either from its name - using the Blot's &lt;code&gt;static create()&lt;/code&gt; function - or from an existing DOM Node.&lt;/p&gt;

&lt;p&gt;In order to use this registry you need register your Blots using &lt;code&gt;Parchment.register()&lt;/code&gt;. With Quill its better to use &lt;code&gt;Quill.register()&lt;/code&gt;, which will call &lt;code&gt;Parchment.register()&lt;/code&gt; internally. For more details on Quill's &lt;code&gt;register&lt;/code&gt; function see &lt;a href="https://quilljs.com/docs/api/#register"&gt;Quill's excellent documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Quill&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Our Blot from earlier&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ClickableSpan&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Quill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ClickableSpan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Ensuring Blots have Unique Identifiers
&lt;/h4&gt;

&lt;p&gt;When creating a Blot with &lt;code&gt;Parchment.create(blotName)&lt;/code&gt; and passing in a sting corresponding to a register &lt;code&gt;blotName&lt;/code&gt;, you will always get the correct class instantiated. You could have 2 otherwise identical Blots with separate blotNames, and &lt;code&gt;Parchment.create(blotName)&lt;/code&gt; will work correctly. However undefined behaviour can occur when using the other form of the method &lt;code&gt;Parchment.create(domNode)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While you might know the &lt;code&gt;blotName&lt;/code&gt; when manually instantiating a Blot, there are instances where Quill needs to create a Blot from DOM Node, such as copy/pasting. In these cases your Blots need to be differentiated in one of 2 ways.&lt;/p&gt;

&lt;h4&gt;
  
  
  By tagName
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quill/blots/inline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Matches to &amp;lt;strong ...&amp;gt;...&amp;lt;/strong&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Bold&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;blotName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Matches to &amp;lt;em ...&amp;gt;...&amp;lt;/em&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Italic&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;blotName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;italic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Matches to &amp;lt;em ...&amp;gt;...&amp;lt;/em&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AltItalic&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;blotName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alt-italic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Returns &amp;lt;em class="alt-italic"&amp;gt;...&amp;lt;/em&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Italic--alt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ... Registration here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case Parchment can easily distinguish between the &lt;code&gt;Bold&lt;/code&gt; and &lt;code&gt;Italic&lt;/code&gt; Blots when passed a DOM Node with the tag &lt;code&gt;em&lt;/code&gt; or &lt;code&gt;strong&lt;/code&gt;, but will be unable to make this distinction between &lt;code&gt;Italic&lt;/code&gt; and &lt;code&gt;AltItalic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Currently the only other way for Parchment to tell the difference between these HTML structures is by setting a &lt;code&gt;static className&lt;/code&gt; that matches an expected CSS class on the DOM Node passed in. If this is not provided you may find yourself manually creating an instance of a custom Blot through its &lt;code&gt;blotName&lt;/code&gt; only to find an undo/redo or copy/paste action changes your Blot into a different type. This especially common when using a common &lt;code&gt;tagName&lt;/code&gt; like &lt;code&gt;span&lt;/code&gt; or &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  By className
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ... Bold and Italic Blot from the previous example.&lt;/span&gt;

&lt;span class="c1"&gt;// Matches to &amp;lt;em class="alt-italic"&amp;gt;...&amp;lt;/em&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AltItalic&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Inline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;blotName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alt-italic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Italic--alt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Returns &amp;lt;em class="alt-italic"&amp;gt;...&amp;lt;/em&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case the &lt;code&gt;static className&lt;/code&gt; has been set. This means parent &lt;code&gt;ShadowBlot&lt;/code&gt; will automatically apply the &lt;code&gt;className&lt;/code&gt; to the element's DOM Node in the &lt;code&gt;static create()&lt;/code&gt; function, and that Parchment will be able to differentiate between the 2 Blots.&lt;/p&gt;




&lt;h3&gt;
  
  
  Insertion and Attachment
&lt;/h3&gt;

&lt;p&gt;Now that a Blot is created we need to attach it both to Quill's document tree and the DOM tree. There are multiple ways to insert a Blot into the document.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;insertInto(parentBlot, refBlot)&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newBlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Parchment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;someBlotName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialBlotValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parentBlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* Get a reference to the desired parent Blot in some way */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;newBlot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertInto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parentBlot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the primary insertion method. The other insertion methods all call this one. It handles inserting a Blot into a parent Blot. By default this method will insert the &lt;code&gt;newBlot&lt;/code&gt; at the end of the &lt;code&gt;parentBlot&lt;/code&gt;'s children. Its DOM Node will also be appended to &lt;code&gt;parentBlot.domNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;refBlot&lt;/code&gt; is passed as well, the &lt;code&gt;newBlot&lt;/code&gt; will be inserted into the parent, except, instead of being inserted at the end of the &lt;code&gt;parentBlot&lt;/code&gt;, the Blot will be inserted before &lt;code&gt;refBlot&lt;/code&gt; and &lt;code&gt;newBlot.domNode&lt;/code&gt; will be inserted before &lt;code&gt;refBlot.domNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Additionally &lt;code&gt;newBlot.scroll&lt;/code&gt; will be set at the end of this call using the &lt;code&gt;attach()&lt;/code&gt; method. Details on that can be found later in this post.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;insertAt(index, name, value)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This method is only available on Blots inheriting from &lt;code&gt;ContainerBlot&lt;/code&gt;. A later post will cover &lt;code&gt;ContainerBlot&lt;/code&gt; in more detail, but the most common of these Blots are &lt;code&gt;BlockBlot&lt;/code&gt;, &lt;code&gt;InlineBlot&lt;/code&gt;, and &lt;code&gt;ScrollBlot&lt;/code&gt;. &lt;code&gt;EmbedBlot&lt;/code&gt; and &lt;code&gt;TextBlot&lt;/code&gt; do not inherit from &lt;code&gt;ContainerBlot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This method will call &lt;code&gt;Parchment.create()&lt;/code&gt; for you with the passed &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;value&lt;/code&gt;. That newly created Blot will be inserted at the given &lt;code&gt;index&lt;/code&gt;. If there nested containers at the given index, the call will be passed to container deepest in the tree and inserted there.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;insertBefore(childBlot, refBlot)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This method is similar to &lt;code&gt;insertInto()&lt;/code&gt; except reversed. Instead of a child inserting itself into a parent, the parent inserts the child into itself. Internally &lt;code&gt;insertInto()&lt;/code&gt; is called and &lt;code&gt;refBlot&lt;/code&gt; serves the same purpose here.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;attach()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;attach()&lt;/code&gt; attaches the calling Blot's parent's &lt;code&gt;ScrollBlot&lt;/code&gt; to itself as the &lt;code&gt;.scroll&lt;/code&gt; property. If the calling Blot is a container, it will also call attach on all of its children after setting its own &lt;code&gt;ScrollBlot&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Updates and Optimization
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note: My understanding of this part of Parchment is still not complete. I will update it in future as I gain a better understanding. If anyone can help fill in the gaps, especially around how many times optimize() may called on children it would be much appreciated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ScrollBlot&lt;/code&gt; is the top level &lt;code&gt;ContainerBlot&lt;/code&gt;. It holds all of the other Blots and is responsible for managing changes made inside of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content"&gt;contenteditable&lt;/a&gt;. In order to stay in control of the editor's contents, the &lt;code&gt;ScrollBlot&lt;/code&gt; sets up a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"&gt;MutationObserver&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ScrollBlot&lt;/code&gt; tracks the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord"&gt;MutationRecords&lt;/a&gt; and calls the &lt;code&gt;update()&lt;/code&gt; method on every Blot who's DOM Node was the &lt;code&gt;target&lt;/code&gt; of a &lt;code&gt;MutationRecord&lt;/code&gt;. The relevant MutationRecords are passed as the parameter. Additionally a shared context is passed with every &lt;code&gt;update&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;ScrollBlot&lt;/code&gt; takes the same MutationRecords and calls the &lt;code&gt;optimize()&lt;/code&gt; method on every affected Blot &lt;em&gt;as well as each of that Blot's children recursively to the bottom of the tree&lt;/em&gt;. The releveant MutationRecords are passed in as well as the same shared context.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;update(mutations: MutationRecord[], sharedContext: Object)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;A Blot's update method is called with the MutationRecords targetting its DOM Node. A single context is shared among every Blot in a single update cycle.&lt;/p&gt;

&lt;p&gt;There are 3 primary implementations of this method in different core Blots.&lt;/p&gt;

&lt;h5&gt;
  
  
  ContainerBlot
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;ContainerBlot&lt;/code&gt; checks for changes that modify its direct children and will either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove Blots from the document whose DOM Nodes have been deleted.&lt;/li&gt;
&lt;li&gt;Add Blots for DOM Nodes that have been added.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a new DOM Node is added that doesn't match any registered Blots, the container will remove that DOM Node and replace it with DOM Node corresponding to the &lt;code&gt;InlineBlot&lt;/code&gt; (basically a plain text Blot) with the text content from the originally inserted DOM Node.&lt;/p&gt;

&lt;h5&gt;
  
  
  TextBlot
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;TextBlot&lt;/code&gt; will replace its &lt;code&gt;value&lt;/code&gt; with the new contents from the DOM Node as it exists in the DOM tree.&lt;/p&gt;

&lt;h5&gt;
  
  
  EmbedBlot
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;EmbedBlot&lt;/code&gt; in parchment doesn't implement &lt;code&gt;update()&lt;/code&gt;. Parchment's &lt;code&gt;EmbedBlot&lt;/code&gt; and its descendant class in Quill &lt;code&gt;BlockEmbed&lt;/code&gt; both have no control over Mutations of their child DOM Nodes.&lt;/p&gt;

&lt;p&gt;Quill's other &lt;code&gt;EmbedBlot&lt;/code&gt; descendant class &lt;code&gt;Embed&lt;/code&gt; wraps its contents with 0-width space characters and sets &lt;code&gt;contenteditable=false&lt;/code&gt; on the inner children. Inside of its &lt;code&gt;update()&lt;/code&gt; method it checks if a MutationRecord would affect the &lt;code&gt;characterData&lt;/code&gt; of these space characters. It it would, the Blot restores the original character data of the affected Node and inserts the change as text before or after itself.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;optimize(context)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;optimize()&lt;/code&gt; method is called after an update pass completes. It is important to note that the &lt;code&gt;optimize&lt;/code&gt; call should &lt;strong&gt;&lt;em&gt;never&lt;/em&gt;&lt;/strong&gt; change the length or value of the document. This is a good place to reduce the complexity of the document however.&lt;/p&gt;

&lt;p&gt;To simplify, the &lt;code&gt;Delta&lt;/code&gt; of a document should always be the same before or after an optimization pass.&lt;/p&gt;

&lt;p&gt;By default Blots only cleanup leftover data from the update process, although a few Blots make some additional changes here.&lt;/p&gt;

&lt;h5&gt;
  
  
  Container
&lt;/h5&gt;

&lt;p&gt;Empty &lt;code&gt;Containers&lt;/code&gt; either remove themselves or add back their default child. Since the length of the document must be the same before and after the changes, the default child Blot must be a 0-length child. In the case of Quill's &lt;code&gt;Block&lt;/code&gt; Blot, that child is a break.&lt;/p&gt;

&lt;h5&gt;
  
  
  Inline and List
&lt;/h5&gt;

&lt;p&gt;Quill's &lt;code&gt;Inline&lt;/code&gt; and &lt;code&gt;List&lt;/code&gt; Blots both use optimize to simplify and make the DOM Tree more consistent.&lt;/p&gt;

&lt;p&gt;As an example, the same Delta&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"insert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bold"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"bold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"insert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bold italic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"bold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"italic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;could be be rendered in 3 different ways.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;bold&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;bold italic&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- or --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;bold&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;em&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;bold italic&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/em&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- or --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;bold&lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;bold italic&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Delta is the same, and this will generally be rendered mostly the same way, but the &lt;a href="https://github.com/quilljs/quill/blob/develop/blots/inline.js#L31-L40"&gt;optimize implementation in FormatBlot&lt;/a&gt; ensures that these items always render consistently.&lt;/p&gt;




&lt;h3&gt;
  
  
  Deletion and Detachment
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;remove()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;remove()&lt;/code&gt; method is often the simplest way to wholly remove a Blot and its DOM Node(s). It removes the Blot's &lt;code&gt;.domNode&lt;/code&gt; from the DOM tree, then calls &lt;code&gt;detach()&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;removeChild(blot)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This method is only available on &lt;code&gt;ContainerBlot&lt;/code&gt; and its descendant classes. Removes the passed Blot from the calling Blot's &lt;code&gt;.children&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;deleteAt()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Delete the Blot or contents at the specified index. Calls &lt;code&gt;remove()&lt;/code&gt; internally.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;detach()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Remove all references Quill has to the Blot. This includes removing the Blot from its parent with &lt;code&gt;removeChild()&lt;/code&gt;. Also calls &lt;code&gt;detach()&lt;/code&gt; on any child Blot's if applicable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This concludes the primary life cycle. Additional Blot methods such as &lt;code&gt;replace()&lt;/code&gt;, &lt;code&gt;replaceWith()&lt;/code&gt;, &lt;code&gt;wrap()&lt;/code&gt;, and &lt;code&gt;unwrap()&lt;/code&gt; will be covered in the next article in this series, "Containers - Creating a Mutliline Block".&lt;/p&gt;




&lt;h2&gt;
  
  
  If you enjoyed this article, keep in touch!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/adam-charron-278678135/"&gt;Join my professional network on LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/CharronDev"&gt;Follow me on Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow me here on Dev.to&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>contenteditable</category>
      <category>quilljs</category>
      <category>parchment</category>
    </item>
  </channel>
</rss>
