Should we use Lexical to edit our legal graph?

Samuel Martineau
Inside Doctrine
Published in
7 min readJun 21, 2022

At Doctrine, since our mission is to simplify access to legal information, we manipulate a lot of text. One of those manipulations is to detect in a given document references to other legal documents using NLP techniques and create connections between the two. This ends up creating a legal graph across all the legal documents.

As part of our platform, we are thinking about offering a textual editor with the ability to write legal documents connected to the legal graph enriched with contextual data.

We started to look at some available popular libraries early in 2022 like quill.js, draf.js, slate.js, and prosemirror. And then, coming from nowhere on the 13th of April 2022, Meta open-sourced Lexical and some Meta’s developers announced that it internally started to replace Draft.js. That’s how we decided to give it a try and see what can be done with this editor.

Disclaimer: This article does not aim to help you choose the best open-source editor in 2022. We decided to test Lexical because we love React.js and we’re not afraid of using cutting-edge technology.

A minimal demo of what you can easily build with Lexical

What is lexical?

Simple

Lexical is an extensible text editor framework. It is minimal. It doesn’t directly concern itself with UI components, toolbars, or rich-text features and markdown. The logic for those features can be included via a plugin interface.

On the one hand, you have an EditorState object composed of:

  • A Lexical node tree. You can think of the editor data model as a simpler version of HTML DOM. You can have nested nodes like paragraphs, links, headings, lists, etc. Sometimes ones can contain others. Additionally to the identifier of the element, you can get extra metadata attached to the node. Technically it’s a JSON tree with a root object with a children key containing other node objects with their children and so on.
  • A Lexical selection object. It represents the current text selected in the editor. It could be used to convert/encapsulate the current selection into a bold node.

On the other hand, you get:

  • listeners that inform you when something happens to the state
  • commands which compose the communication system used to wire the editor actions to the lexical state. Useful when you want to expose a button somewhere on your interface to control the current editor selection.

Extensible

By defining a custom node and custom plugin, you can enhance the editor with no limit.

A node is a javascript class that extends at the end, a LexicalNode. There are 5 core-based nodes. Three of them are exposed from the lexical package to allow you to build custom nodes on top.

Sometimes you will use Enhanced nodes exposed by the official’s supported packages like LinkNode for hyperlinks or HeadingNode to handle title levels.

How to extend lexical nodes

Community

Since the library is under development, the documentation is not complete and structural changes often happen.

It’s clearly something to be aware of when you want to build a product on top.

But it also comes with opportunities to take part in the open-source community with some simple first-time issues like correcting and improving the documentation.

The lack of documentation also leads to talking directly to the creator of the library. The Lexical core team offers a direct line to contact them through Discord Channels. I experienced it to crack an issue I had with deserialization (conversion from HTML to Lexical data model).

How could we use it at Doctrine?

If you want to start by reading the code, you can check out our demo repository here: https://github.com/DoctrineLegal/blog-posts/tree/master/lexical

if you prefer testing the result, go to our live demo here: https://doctrinelegal.github.io/blog-posts/lexical/build

How to extend a LinkNode to automatically custom visual?

My first attempt was to try enhancing a link with a custom style to distinguish a resource corresponding to an entity of our legal graph from an external resource.

toggle selection into a link

We achieved this with a custom node extending the LinkNode provided by the lexical link package.

What you have to do is implement some method to override the standard ones. You have to define your own type with a unique name, and the customization of the link comes from the createDOM method.

SimpleLegilsationNode.tsx

The last part of the demo deals with the way selected text is being converted to a link. The code is totally inspired by the official link package. It toggles text to link and link to text according to the URL you provide. It also handles logic to check if you have selected a text child embedded in a link parent.

How to create a custom Decorated Node and Why?

ElementNode needs to be atomic, you can’t create a complex DOM structure. Moreover, you may want to code your complex structure with a framework like React.js. This is where DecoratorNode is useful.

RichLegilsationNode.tsx

You just need to implement the decorate method of DecoratorNode to pass a custom React Component to your Node. It will be rendered as a child of the DOM node you defined in the createDOM method.

You can now add as much data as you want on this node. In our demo, we use a legislation key which is a “complex” object, and a comment key to store a string.

Insert Custom Node

How to convert a selection into a custom node?

We have seen how to append a new custom Element to our editor. Now we want to convert a selected text into our custom Element.

Use and replace the current selection with a Custom Node

This feature is based on two commands:

  • one to send the current selection to the Legislation Detector which acts as an auto suggester (DETECT_LEGISLATION)
  • one to send the selected legislation selected to the plugin that will convert the text selected with the legislation (CONVERT_SELECTION_TO_RICH_LEGISLATION_COMMAND)
RichLegislationNode.tsx

In the end, we get the current selection, extract the lexical nodes involved in this selection and then we replace the text with our new Custom Node created.

How to export/import custom Node?

This part of Lexical was a requirement for us. It relates to how you persist, store and reload the data. Since we have created a custom Node, we need to explain how the data need to be converted into JSON object.

RichLegislationNode.tsx

Lexical offers export & import helpers from @lexical/file to allow you to store the EditorState as a file and load it back to your editor.

Export / Import Editor State

How to convert HTML to custom Node?

The last part of Lexical we were interested in was the Serialization/Deserialization used under the hood when copying/pasting the content of your clipboard into the editor.

The feature is powered by a DOMConversion notion based on two things:

  • a conversion method that converts an HTML node into a Lexical one
  • a priority to define if your Node has the priority on a given tag. Example hyperlink could correspond to multiple Node and it’s the case in our demo.

By implementing the importDOM method of LexicalNode we can run business logic to decide if we want to convert a given HTML tag into a custom Node.

RichLegislationNode.tsx

This could be very useful for use if we need to load content received from authors that probably will write their content in Word or Google Docs.

Import raw HTML to Lexical

I hope this could help you access the core concepts of Lexical.
Feel free to check out the code and try the demo

Conclusion

Playing with Lexical provided us with a lot of insights to better understand how an editor works and what concepts are involved. This is something we will need for our future squads that will work on making our legal graph more scalable.

We haven’t yet explored the collaborative side of editing but it’s a completely different business so we don’t know yet how far we are getting to go in that direction.

So if you want to come to help us build an open and more connected legal intelligence platform, feel free to apply here.

--

--

Samuel Martineau
Inside Doctrine

If you want to join me and work on exciting projects at Doctrine, feel free to ask me here: https://cooptation.hellotrusty.io/zqo343sglg