Minimum viable rich text editor for Svelte 5?

Last year I wrote in detail about the state of web-based rich text editing. Not much has changed since. It’s still way too hard to create a custom rich text editing experience for the web and I still recommend using ProseMirror if what you need is essentially a classic document editor (think Microsoft Word).

However, I’ve been exploring new territory for the last year or so. As you may know, our latest grand challenge is making websites in-place editable. So instead of having a backend (the CMS) and a front-end (the website) the two interfaces are blending into another, becoming just one.

Since there is no backend/frontend separation anymore, it’s essential that our text editing solution is extremely minimal. We can’t afford pulling in ProseMirror or Lexical, as that would be too much Javascript to load for people who are just viewing, but not editing a page.

Introducing Svedit

Thrilled by the capabilities and simplicity of Svelte 5, I started working on a simple Svelte component <Svedit> (think ProseMirror but in less than 1000 lines of code). Under the hood it’s just a div with contenteditable=true, but it keeps that div in check. So instead of letting the browser do its crazy thing, we will intercept input events, manipulate the string that the Text component manages, update the DOM and set the selection after the new character. That cycle repeats for each keystroke.

Here’s a brief list of requirements:

  • Reliably edit plain text inside a div (or other HTML element)

  • Ability to insert annotations (e.g. strong, emphasis, link) as separate data (similar to Bluesky’s Text Facets), not as markup. To keep things very simple, annotations must not overlap.

  • Pasting any content from the clipboard will result in a reasonable plaintext version being inserted, all markup is stripped and converted to annotations/facets where appropriate (e.g. links, bold and italic)

  • Ability to add newlines (Cmd + Enter)

  • It should be possible to have multiple <Text> instances on one page and navigate between them with the cursor keys.

The bigger context

In the simplest case Svedit can be used to replace an ugly textarea and support basic annotations. However we also want to be able to add one or many <Container> components, that maintain a list of custom <Block> components. The idea here is that you can do classic Svelte development, and implement <ImageBlock> for instance, while you can place a <Text> Element for the image caption, allowing users to either view that caption or edit it right in place.

We already have that working more or less (see above screenshot) but our existing solution suffers from limitations:

  • Undo/redo works on text level but not on block level, so you can’t undo deleting a block for instance.

  • We are only supporting plaintext during editing, so we enabled Markdown for simple things like bold, italic, and links. But then it’s no longer real in-place editing, requiring you to save the changes before you see how the result will look like.

  • There were also issues when navigating from one container to another (invalidate selections), and we currently aren’t able to fully control the layout of a container (e.g. mixing vertical containers like a classic list of paragraphs and horizontal containers like a list of menu items).

  • Cut/copy and paste of multiple blocks inside a container is not possible atm, which really slows you down.

So we want to get rid of those limitations, do some cleanup and generalization, and make this available either as a library or as a template repository where you can copy & paste a bunch of files into your own setup. There’s already some good progress, but things will take a bit of time to marinade and stabilize.

Until then, let’s pray browsers will one day make all this dance with contenteditable obsolete. There is some hope that the new EditContext API will change things for the better. Currently this is only available for Chrome though.

Published by Michael Aufreiter on Aug 29
Revised on Sep 2
1 Conversation

That would be exactly what I’m looking for right now.

No replies yet
Be the first to respond.
Respond to the author

On Ken, we're trying to figure out how the world works — through written conversations with depth and substance.

Your response will be public, and the author will be notified.