How to Build a Notion-style editor with AI-powered autocompletion
TLDR: In this article, we will explore a high-level design of Potion —a Notion-style email builder with AI-powered autocompletion. Also, I just launched Potion on Producthunt.
Let’s get started.
Requirements
Rich-text editors come in all shapes and forms e. g., editors in apps like Substack, Medium and even Notion.
But let’s take these one step further and create an editor not simply capable of text inputs, but includes interactive nodes and exports to valid email HTML.
- The editor must be capable of supporting text (without any character limits)
- The editor must support rich content such as images
- The editor must support email template nodes such as buttons and dividers
- The editor must be able to support layout columns e.g., a 2-column or 3-column layout
Here’s an example of Potion with the Netflix email template:
High-level design
I’ll skip the overall system design (databases, API gateway, edge middleware etc.) and focus solely on what goes on in the clients:
1. The Potion Editor
The main components of our editor include a global state and associating view and model.
To parse the editor state and render valid email output, the entire content of the editor is powered by a very strict schema (model) that enforces what’s possible and visible to a user (the view).
For a rich extensible headless editor, I chose Tiptap.
2. The Potion Renderer
When a user previews the editor content, they must get the same visual representation but an HTML output. To be specific, XHTML 1.0 (the markup supported in most email clients)
The potion renderer takes an object representation of the editor state, walks the entire tree and maps each view item to corresponding email-compatible markup while keeping the same styles and output.
If you strip away the custom code for walking the tree and other business logic, the email-compatible components are provided by react-email.
In a nutshell, the potion renderer could be summarised as state (object) + theme (object) = React Fragment nodes [] eventually rendered to HTML by react-email.
When you bring it all together, you have a combination of two main components.
Shameless plug: Support Potion on Producthunt
Worthy mentions
If we zoom into one of the editor components (view), our design must include custom nodes such as buttons, images, layout grids etc.
These aren’t supported natively by Tiptap. However, the underlying editor used by Tiptap, prosemirror, supports plugins — there’s also an associated API within Tiptap.
This means we could define custom schemas and associating nodes.
What about AI autocompletion?
AI’s all the rage these days, and for good reasons.
Except you’re fine-tuning an open-source model or creating a custom model, creating streaming UI interfaces isn’t a complex feat.
The easiest way to build this as a React developer is to use the Vercel AI SDK.
This is how Potion works under the hood as well.
Conclusion
There are many interesting technical challenges with building such an editor. I could write a series of blog posts on this. Ultimately, this was fun to build!
P.S.: Check out Potion on Producthunt.