Pirobits
  

Developing an HTML editor in React.js (WYSIWYG)

alberto avatar Alberto Sola · 2/19/2025

These past few weeks, I’ve been exploring different Markdown editors for a side project. It all started as a simple text-area where I manually copied the Markdown I edited in some other editor (Obsidian, Notion, Dillinger). Then, I tried adding a WYSIWYG preview ("What You See Is What You Get"), and I ended up exploring different options to avoid reinventing the wheel: ProseMirror/CodeMirror (used by TipTap), Ace (which seems abandoned), Draft.js (deprecated), and Lexical.

Image of my CMS with the editorWhile researching, I found that Obsidian uses CodeMirror internally, Dillinger.io uses Ace (which hasn’t been updated in 7 years—it's still using Node 16). Then there’s Lexical by Meta, which seems super powerful but lacks proper documentation, making development a real headache. After reading a lot, the best option is to use TipTap, which is clearly well-maintained by a dedicated company. The editor is open-source and runs on CodeMirror / ProseMirror, which at least have more documentation available.

After several days of reading and developing, I found it interesting to study how these editors work internally. It turns out there are mainly two approaches:

  • Using a "hidden" textarea that acts as a proxy to a div. The textarea handles input/output but has the limitation of not allowing styles or colors, so a div is used to display the content.

  • Using a div with the attribute contenteditable=true. This allows the browser to capture all necessary events, which we then intercept and manage in the component state: every time a key is pressed, we compute text modifications, render them, then transpile to HTML and inject them into the div for rendering.

Sounds easy, but trust me, it’s not. There’s a lot of complexity in different areas, though it’s super interesting. So, why not give it a shot? Curiosity always drives me to experiment with these kinds of things.

During college, I loved the compilers course, where we built our own syntax that compiled to C++. Since then, I’ve been fascinated by automata, lexers, parsers... Plus, it's a highly relevant topic in frontend development today, especially with Rust initiatives like SWC/Turbopack on one side, and void0 working on RollDown and Vite 6, or TikTok's RsPack. But anyway, back to the main topic.

These past few days, I’ve been working on a proof of concept. It’s way more complex than it looks and requires a ton of work: What data structure should be used? How should HTML events be managed? Is it better to maintain an internal state and render it later, or not?

I found it interesting to upload the editor code to a GitHub repository in case anyone else wants to experiment with it. Right now, it's just a PoC, with some keys not implemented yet and a few edge cases to handle properly. I don’t plan to continue working on it for now.

Did you find this article useful?Join the community to receive exclusive content!

Learn how to launch your product

I share my learnings on the journey of creating and evolving products. I cover all sorts of topics, from personal growth to articles or books to learn and improve on the entrepreneurship path.Are you ready to learn with me?

More than 50 creators are already learning with me 🚀

The most recent posts I wrote in the blog