A one-sentence introduction

Slate-angular is an editor view layer based on Angular and slate.js that helps developers build Web rich text editors using Angular + slate.js.

Slate. Js is introduced

Slate.js is an excellent rich text editor framework with clean code, good architecture and strong scalability. At present, there are numerous rich text editors and products developed based on Slate.js in the market. In addition, Slate.js is magic enough. From the beginning of the rich text editor development to the present two years or so, I feel that Slate.js has been a good teacher for my growth, from the initial introductory research, to the development of the first version of the editor, then the upgrade of the view layer architecture, and then the performance and stability optimization. There’s a lot to learn from Slate.js at each stage, and a lot to learn about it. I think Slate. Js is a itself in constant iteration and improved editor framework, focusing on the view layer and model layer, architecture implementation has been followed by community mainstream technology development, the implementation mechanism of content editing is in constant to the current standard events, have open source 5 years or so, the community is still very active, It is still expanding to more and more scenarios, and it is a very impressive existence.

Develop your own Angular view layer

Angular is our front-end technology stack, and rich text editors developed based on Angular are extremely scarce in the open source community. The PingCode Wiki product we are going to make has very high requirements on the ease of use and scalability of rich text editors. The survey found that Slate editor framework is very suitable for our needs. The core model layer does not rely on any front-end framework, is extremely extensible and has complete test coverage, so we tried to develop our own Angular based view layer, which can be understood as the core driver of our own view layer comes from the product.

Personally, developing an Angular view layer is a very interesting process, and there is currently no implementation of the Angular Slate editor in the open source community, so we wanted to open source our practice and give back to the Slate and Angular community. Make rich text editors available to more developers based on Angular + Slate.

The road of open source

Currently, Slate-Angular has supported PingCode Wiki, an enterprise-class knowledge base product, for over a year. The original version was based on [email protected] (JavaScript version SLATE). Release 2 is a TypeScript implementation based on the latest Slate. The third version of TypeScript has been in preparation since the beginning of this year, including opening the Github repository, unifying the underlying implementation and API style, building online demos, adding unit tests, and updating the latest Slate simultaneously.

The Demo function:

Github:github.com/worktile/sl…

Demo: slate-angular.ngnice.com/

Slate-angular may not be a rich text editor out of the box. It is a view layer of the SLATE framework, a middle layer that connects the bottom layer of the SLATE framework to the user interface. It only provides slots for basic rich text editing capabilities and functionality extensions, but this is the advantage of Slate-Angualr. It only focuses on the underlying implementation: Compatible with browsers, mobile terminals, proxy input events, proxy cursors, support for custom Element/Text/Leaf node rendering, processing basic interaction, etc. Based on it, rich Text editors with certain basic functions like Quill and Prosemirror can be developed quickly, and its scalability limit is very high. It is possible to build rich text editors at the Confluence, Notion, PingCode Wiki level over time.

Feature supports

  • Integrates the block-level element before and after cursor scheme

Support for extending the cursor before and after the specified element rendering to facilitate the insertion of paragraphs before and after block-level elements (basic interaction with the block-level cursor is already implemented in table Demo)

  • Custom components/templates render block-level elements

Support for custom rendering of multi-level element content to facilitate the implementation of complex scenarios such as tables, while maintaining the correct dependency injection chain between custom components, that is, cell components can obtain the services of the parent table component through dependency injection

  • Custom render Text

Support custom render the contents of a Text node, this is not provided in the SLATE – react SLATE – presents proposed separately, it is mainly used for bold, italic, underline, color, background color, etc

  • Custom render Leaf

Leaf is the separation of Text, each Text node corresponds to a Leaf by default, and the separation of Text nodes is based on Decoration, which is mainly used to achieve dynamic modification of Text. Cooperate with the custom Leaf component to achieve search highlighting, underline comments and other requirements

  • Decoration decorator

Provides dynamic modification of text content, which is driven by external data to locate and decorate text content. It is characterized by the implementation of text decoration without changing the original data, is a way to deal with dynamic requirements

  • Void element

Void means not editable, and everything is a whole. Slate-angular extends the Void element to embed any complex Angular component into the editor’s content area, such as images, code editors, gantt charts, etc.



Compatible browser

Chrome, Edge, Safari, Firefox, QQ Browser



Common Slate.js compatibility issues have been resolved

  1. Chinese input duplication problem

  2. Chinese input crash

  3. Safari browser input Chinese focus jump

  4. \n Leads to content confusion

  5. A Tag causes confusion

  6. Table structure constraint problem

  7. Presents the comment problem

  8. .

These Issues have been resolved in Slate-Angular. No further explanation will be provided here. If you have any questions, please feel free to contact Slate-Angular.



Technical route

Next, let’s talk about some technology related content. In fact, I have always wanted to analyze the architecture design and internal mechanism of Slate.js, so I take advantage of this open source to briefly talk about the technical route of Slate.js and Slate-Angular and some important underlying mechanisms.

Start with the Slate architecture:

The core of Slate framework consists of model layer and view layer. The model layer defines the basic data structure describing rich text content (a node tree supporting nesting) and the basic operations on the data. The view layer connects to the front-end framework, processing basic input behavior, selection proxy, content rendering, plug-in extension and so on.

It is worth mentioning that the definition of Slate’s data model is implemented according to DOM standards, which is relatively friendly to novices. For example, the concepts of data model Block, inline-block and Text are consistent with the meaning in DOM. Electoral districts also include Selection, Anchor, Focus, and Collapsed.

Slate rich Text editor architecture overview:



Develop rich text editors based on Angular

Slate-angular, as an independent view layer, serves as a bridge between the bottom and top layers of SLATE functionality. The core role of Slate-Angular is to take advantage of the framework to better organize the development of editor functionality.

Developing a rich text editor based on Slate-Angular is true to Angular. Instead of wrapping JavaScript libraries with components, you can use angular components or services to organize code for basic feature changes and extensions:

You can customize plug-in rendering using Angular components or templates.

You can encapsulate complex interactions based on Angular components.

You can reuse Angular component libraries.

You can also use services to share data between parent-child node components that maintain the correct dependency injection chain.

All Angular features are available to you.

Fundamentals of content editing

Under the framework of the current technology to achieve control of the input approximately two realization ways, one is event agent, additionally one kind is to monitor content changes, Slate mainly adopts is the event agent is the DOM events by monitoring a series of content input, and then through the event type and other context determine the input corresponding data operation, Finally, this is translated into a series of operations on the data model.

The way to monitor content changes is also useful in Slate, in order to support the Android browser, presumably because there are certain scenarios in the Android browser where input events are not captured correctly and therefore cannot respond to user actions. So use MutationObserver to monitor content changes to properly respond to user input behavior.



Because the view layer in the event the realization of the agent is mainly deal with input events, each browser for input events not achieve complete reunification, and to distinguish between ordinary combination of input in English and Chinese input, so you need to do a lot for different browsers compatibility, can say is a combination of playing style overview:

  1. Ideally: Use beforeInput events to complete the base input proxy, because beforeInput is semantically clear and can be used as a standard for determining input behavior.

  2. Not ideal: Browsers do not support beforeInput events. Use the React composite event onBeforeInput to handle English input (Angular requires its own implementation), and keyDown events for other input interactions such as enter and delete.

  3. IME input processing is handled using the compositionStart and ComPOSItionEnd events, which are very reliable without any browser compatibility issues.

  4. In addition, undo/redo, focus shift, etc. are handled in keyDown events. Logic such as copy and cut uses native copy and cut events. Logic such as paste and drag relies on beforeInput events as well as basic inputs. If the browser does not support beforeInput events, they are processed in paste and DROP events.

Event broker process overview:





Selection synchronization mechanism

Like the browser’s selection, Slate’s data model requires selection, identifying the location of the data changes as they occur, and keeping this location consistent with the browser’s native selection.

Here’s the bidirectional synchronization of selections in the Slate-Angular view layer:

DOM Selection -> Slate Selection:

Monitor the selectionChange event of the native Document object, query the corresponding Slate Selection when the DOM Selection changes, and modify the Slate Selection to be consistent with the DOM Selection.

Interactive behavior -> DOM Selection change -> SelectionChange -> Sync Slate Selection

Interactions include mouse clicks, arrow keys, and so on



Slate Selection -> DOM Selection

The Change of Slate Selection data results in the Change of Slate Selection, which needs to be processed in the Change event. According to the latest DOM Selection query, Modify DOM Selection to be consistent with Slate Selection.

Interaction -> Trigger data update -> New Slate Selection -> View refresh -> Sync DOM Selection

Plug-in extension

Slate uses plug-ins to extend editor functionality, and plug-ins are first-class citizens (slate-Angular can also be understood as a basic plug-in), and any advanced interaction can be implemented by developing editor plug-ins.



Rewritable methods

Slate layer abstracts rewritable methods one by one (deleteBackward, insertBreak, insertText, apply, etc.) for external extension. For example, if I want to recognize Markdown data format when pasting, I can rewrite insertText implementation. InsertBreak can be overridden with carriage returns. Providing a rewritable method is a more advanced implementation than directly exposing the underlying event. Several rewritable methods are also provided separately in the Slate-Angular view layer: InsertData (handling paste data), isBlockCard (block-level cards), onError (error handling), onKeydown (base events).

Second, custom rendering

The UI part of the view layer is mainly composed of three layers of rendering, corresponding to three layers of data: Element, Text and Leaf. Data of each layer supports custom component/template rendering, mainly through renderElement, renderText and renderLeaf.

View layer custom render component process overview:





This section introduces some of the most relevant slate-Angular parts: Component-based development editor, event broker, selection synchronization, plugin extensions, etc. The core hope is that you can learn more about Slate. js and slate-Angular, as far as the technology is concerned, you can read the source code or other technical materials.

Write in the last

Rich text editor is a very complex in front of a domain, the future of the road is still long, we also hope to have more developers to participate, to find and solve, such as browser compatibility, compatible with the mobile end, Chinese input, the standard interaction problems, optimize the input agent mechanism, optimize the underlying architecture, explore collaborative scheme based on Slate, etc.

If you have any questions, please contact Slate-Angular for Issues or PRs!