Stesura

Why we built Stesura

Edoardo Caratti,•6 min read

Why we built this and why you’d want it too

After some years in the legal industry, we were looking for a contract automation tool that could solve the pain points we had. Word just didn’t cut it. Too clunky, too restrictive, and it just was not the streamlined experience we wanted to give our users. So we started looking. The market is flooded with tools, editors, etc., but for some reason, none of them fit our requirements:

Basically, a web-based word processor with a modern API and a tree data model.

Reality check

That doesn’t exist.

We were stuck between exporting to Word and creating a JS plugin that would be used in a Word document. But that’s not an experience we were too excited about, and it doesn’t solve half our problems. There are tools out there like OnlyOffice or Syncfusion — they give you everything you could want from a word-like editor and it’s embeddable! But not really extensible… We were feeling optimistic about CKEditor or TinyMCE — loads of features out of the box, extensible, well established — but they’re still miles away from the level of customization we needed. And to be honest, we weren’t feeling too confident about extensively building on top of someone else’s large codebase, under their licensing terms…

So we started looking for alternatives. Trix, Slate, Quill, Tiptap, ProseMirror, Remirror, Draft.js, Lexical, and many more… Rest assured, we’re not nearly mental enough to even consider building one from scratch.

Why we chose Tiptap and ProseMirror (at first)

None of them had anywhere near the level of features we needed out of the box, but they all had good APIs, mostly or fully open source, and a community that already had drawn a path for us and the features we needed. At the time, ProseMirror was well established, Tiptap just entered its v2, and we had a good feeling about it. The community was there and growing, and Tiptap gave us the confidence we needed to start building with Tiptap and ProseMirror. And what can we say, we just loved the experience that came with the Tiptap-ProseMirror integration, its data model and the benefits a strong schema brought to the table.

So there we were, on our merry way to build our legal word processor and our contract automation tool. We kept adding features on top of Tiptap, but performance concerns were slowly creeping in.

Why we started looking for alternatives

Honeymoon period over. Sure, the team at Tiptap did a lot of work to make their editor performant, but we needed nodeviews, and they all came at a cost in Tiptap. Each React nodeview gets mounted through its own portal, with its own wrapper element, and with hundreds of them on a long document, the overhead we were seeing was starting to make us think we wouldn’t be able to do this. Don’t get us wrong, we love Tiptap, their product is great, the team is amazing, and the work they made for the community is invaluable. And it’s fantastic if you need a relatively simple editor out of the box with all the perks of their and ProseMirror’s API. It just wasn’t for us. You can read more about our experience with Tiptap in our blog post about ditching Tiptap.

For a while we kept building on top of Tiptap, at least we were moving forward hoping a magical fix would come along. It didn’t. So we started looking for alternatives.

Our Lexical period

The new kid on the block, Lexical, was very promising — built at Meta by some heavy hitters, it had a framework-agnostic core with official React bindings, it was extensible and extremely performant. So we dug into the documentation, and let me tell you, coming from Tiptap and ProseMirror, it was rough. The API definitely wasn’t as friendly coming from Tiptap and ProseMirror, and the community was a lot smaller, so reading open-source code of open-source plugins wasn’t something we could easily do. And then this blog post  hit. So there went our confidence in Lexical out the window for a 200+ page word-like editor…

React-prosemirror. An absolute godsend.

Then a new blog post  from Smoores, the author and maintainer of react-prosemirror, hit the ProseMirror discourse. The performance was amazing, it was React-based, we were back to something we were familiar with and nodeviews were part of a single React tree, no more portals, no more per-nodeview overhead, no more performance issues (edit: and then he dropped this banger ). We were sold.

The library is dead simple to use, the documentation is excellent, and it relies on vanilla ProseMirror. So we moved all our code from being written for Tiptap’s extension model to being written as simple ProseMirror plugins. And boy, let me tell you, there is not a single day we regret it. Sure, it took us a while to get the hang of it and we sorely missed Tiptap’s extension model and API, but it was standing in our way to understanding ProseMirror at a deeper level. So if you’re reading this and want to develop a performant word processor for the web and you’re still using Tiptap, we highly recommend you give react-prosemirror a try. But if you’re just looking for an easy editor and don’t need a very high level of complexity and don’t deal with hundreds of pages, Tiptap is a great choice.

So you’re looking for a word processor and are still not sure what to choose?

“We don’t do this because it is easy, but because we thought it was easy.” There’s a reason text editors are considered the final boss of frontend. It fought us on every level. But through perseverance, great timing from some fantastic libraries and a lot of trial and error, we finally got there.

This has led us to release Stesura, a word processor that is built on top of react-prosemirror and is designed to be a performant, extensible and feature-rich word processor for the web. We made it performant, extensible and feature-rich, so you don’t have to decide between using a feature-rich editor with low extensibility or take months developing your own.