How to Build a Notion-style editor with AI-powered autocompletion

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.


Rich-text editors come in all shapes and forms e. g., editors in apps like Substack, Medium and even Notion.

Modern rich editors

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
A summary of the requirements

Here’s an example of Potion with the Netflix email template:

Editing a Netflix template with Potion

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.

The Potion editor

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.

Leveraging 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

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.

From Potion renderer to email markup

If you strip away the custom code for walking the tree and other business logic, the email-compatible components are provided by react-email.

Leveraging React email for email markup render

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.

The major components of Potion
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.

Custom Potion nodes

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.

Custom nodes

What about AI autocompletion?

AI’s all the rage these days, and for good reasons.

AI autocompletion in Potion

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.


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.