In our everyday interactions with productivity tools, using input boxes is a given. They're integral to crafting documents, managing tasks, and facilitating online communication.
Most of the time, the architects behind these productivity tools are tasked with creating a straightforward input box. It's a space designed to accommodate plain text, perhaps with the addition of font colours, bold, and maybe mentions.
However, when building an inbox with an in-built email editor, there are significant layers of complexity. Users require intricate formatting, inline multimedia and attachment support, the list goes on.
At Compose, we set out on a mission to re-imagine the inbox experience. However, we soon realised that the pain of getting the input box right was holding us back.
Back in 2019 we chose to use Slate.js as our rich text editor library. At the time this decision felt right, but as we grew it became clear this option didn’t support our users’ needs or our product growth goals.
Our input box only offered basic formatting. Users wanted more than we could provide and we had an ever-growing backlog of bugs. The user experience was awful and it was eating up development time unnecessarily.
For Compose to grow, it was clear that it was time for a fresh start. We needed to re-imagine the inbox by first re-imagining our email editor.
Step 1: Getting clarity on what we wanted
Our journey started by looking inward. We dug into our own personal experiences of our input box, gathered user feedback, and compared it to the sleek, modern editors on the market.
This deep dive laid the groundwork for the improvements we needed to make. We pinpointed features we wanted to incorporate, which went much further than the standard inline styles.
Here’s a snipped of what our list looked like:
We then worked to find a library that could help us achieve these goals and bring our vision to life.
Step 2: Finding React rich text editor libraries
We knew we needed to re-evaluate our options and explore newer libraries that had gained popularity since our original decision to use Slate.js.
As we began our search, we were amazed by the sheer number of rich-text editor libraries available. With so many options to choose from, it was easy to feel overwhelmed, but here’s the comprehensive list of candidates we settled on:
Step 3: Setting criteria
When it came to assessing them, we knew that simply choosing a library that offered the features we wanted wasn’t enough. We needed to consider a whole list of criteria to ensure that it would be the right fit for our project.
We considered factors like API stability, customisability, extensibility, and community support.
We went deep into our analysis, looking into the libraries’ implementation times, their age (seeking a balance between stable APIs and avoiding stale technology), and whether they blocked extensions (e.g. Grammarly).
If you’re weighing up different libraries to use for your product, here’s a list of criteria we wrote up which should be helpful to get started:
Top tip: ****don’t forget to turn to Twitter. It proved invaluable for gathering real-world insights on each option.
Step 4: Whittling down
Once we were clear on our criteria, assessing libraries became a quick process. We were easily able to eliminate some options due to bug reports, outdated tech, or steep learning curves.
When looking at some of the bigger libraries on the list, like Quill and Prose Mirror, we had to think a little deeper.
Quill is one of the most popular and well-known libraries, created in 2014 with the aim of simplifying the process of creating rich text editors. It initially seemed like a good framework due to its focus on simplicity and ease of use, appealing if you want a “drop-in” editor. However, it appears that performance issues occur as you delve deeper and seek customisability. A quick search on Twitter revealed that this has become a recognised defect, so we ruled Quill out.
ProseMirror was created in 2016 and is thought to be one of the most feature-packed and powerful frameworks available. It’s thought that you can’t get much better than Prose Mirror in terms of customisability. The documentation is also excellent, with a lot of examples to help you get started. However, we ultimately ruled out ProseMirror because its API is more complex than other libraries, with a steeper learning curve. Even the authors admit that starting from scratch requires a lot of code. While ProseMirror provided many powerful features, this ultimately meant it did not appeal to us.
Through this process, we eventually whittled down our shortlist to three top contenders: Editor.js, Tiptap, and Lexical.
Step 5: Vetting top contenders
Now it was time to get familiar with these libraries through testing. And we left no stone unturned.
Firstly, we examined the documentation of each contender thoroughly, looking for it to be comprehensive, up-to-date, and easy to follow. This also gave us more insight into the number of available plugins and extensions.
The second step was examining Codesandbox examples or other open-source projects that implement each library. This helped us assess the overall quality of the codebase, the performance, and the ease of use.
But it was the third step that really helped us get clearer on our decision.
We utilised the demos, or “playgrounds” provided by each library to get hands-on experience. This allowed us to explore the editor’s features and test how they worked in practice, as well as getting closer to the user experience of each library. Take a look at those of Lexical, Tiptap and Editor.js to see how they work.
We even took it a step further by testing each library against our current input box bugs. We checked if they glitched on indentation of lists, if backspace worked on mentions, and if formatting was retained on copy and paste.
Slowly but surely, we were getting more sure on the best option for us.
Step 6: Bringing in the engineers
Naturally, the R&D of this project was not something for the product team to completely own.
The next step of our journey was to bring in the engineers to ensure that our final choice was technically sound, compatible with our existing tech stack, and aligned with their capabilities and resources.
Collaboration brought up some important concerns around Editor.js and Lexical:
Editor.js had initially won over the product team with its sleek UI, which was similar to that of Notion's. However, our engineers ruled it out due to its block-based approach to content. While this approach allows for easy rearrangement of content, it also meant that the library's support for some features was hit or miss. They also found the customisation options were limited, making it less flexible and easy to use than they would have liked.
Lexical seemed promising to the product team due to its speed, reliability, lightweight nature, and accessibility. It is also currently being used in production at Meta, which is a good sign. However, after consulting with our engineers, it became clear that Lexical was too new and possibly unstable. With our growth trajectory, we couldn't risk major API changes affecting our app's compatibility with future updates.
Step 7: Decision time
After careful consideration, the Compose team unanimously decided that Tiptap was the ideal backbone for our new email editor.
Here’s why:
Let's start with its robustness and stability. It's built on top of ProseMirror, which as I’ve mentioned, is a powerful toolkit for building rich text editors that has been battle-tested. This foundation gives Tiptap an edge in terms of reliability and performance.
The simplicity and ease of use of Tiptap are also worthy of praise. Our problem with ProseMirror was its complex API, but the one Tiptap provides is clean and well-organised, providing developers with a familiar and efficient way to work. It makes the complex task of implementing a rich text editor as straightforward as possible.
Tiptap's customisability is second to none. You can customise your editor to do exactly what you need, whether that's adding tables, mentions, a floating toolbar, or YouTube embeds. And it's not just about adding new features. The style and behaviour of the editor can also be tailored to match your requirements, ensuring seamless integration with your application's design.
Furthermore, Tiptap is built with cross-platform compatibility in mind. It ensures that your users will have a consistent and high-quality experience, no matter what device or browser they're using.
Lastly, Tiptap benefits from a thriving community of developers. Its GitHub repository has a significant number of stars (18.4k), demonstrating its popularity within the developer community. This active community translates into a steady stream of improvements, a wealth of shared knowledge, and robust support when you encounter issues.
All of these factors truly set it apart.
Since implementing Tiptap, we've boosted our functionality tenfold. We’ve ticked off the original list of features we wanted, and even taken it further.
And behind the scenes, it has been a game-changer in terms of reducing our technical debt. We’ve slashed our backlog of input box tickets, enabling us to reallocate resources to focus on further product improvements.
But perhaps the most significant outcome of adopting Tiptap has been the positive user response.
We have been inundated with messages from happy users who have loved the upgraded functionality and visual appeal of our email editor. Such a simple change has led to a huge increase in user satisfaction and engagement, validating our choice to prioritise this crucial aspect of our app.
I hope our experience and insights will help anyone else who wants to improve their current input box, or even build a new one.
Our journey has taught us lots of valuable lessons, so here are 4 tips to set you on the right path:
Of course, we highly recommend Tiptap - it really is a powerful, flexible and reliable rich text editor library, that is a joy to use.
Don’t hesitate to reach out and tell us your experience of Tiptap, or any other library you’ve used. I would love to hear your thoughts!