Should we build a Paragon native text editor?

Hi!

When working on the exemplar-blocks [1], I noticed that the bundle size of an XBlock’s UI jumped 4x after adding TinyMCE for an input field.

Before

vite v8.0.2 building client environment for production...
✓ 3292 modules transformed.
computing gzip size...
../src/card_grid_block/public/cardGridStudent.js   28.15 kB │ gzip:   7.19 kB
../src/card_grid_block/public/Stack-CMSfB8yk.js   286.74 kB │ gzip:  75.12 kB
../src/card_grid_block/public/cardGridStudio.js   580.87 kB │ gzip: 153.31 kB

After

vite v8.0.2 building client environment for production...
✓ 3309 modules transformed.
computing gzip size...
../src/card_grid_block/public/cardGridStudent.js     28.15 kB │ gzip:   7.19 kB
../src/card_grid_block/public/Stack-CMSfB8yk.js     286.74 kB │ gzip:  75.12 kB
../src/card_grid_block/public/cardGridStudio.js   2,291.73 kB │ gzip: 609.56 kB

This got me thinking about a “Paragon Native” text editor. Using the Lexical editor framework, and the code sample from the home page, I ended up with the following PoC.

It does what you see in this image below:

and builds to around ~700 to ~900KB based on the format:

> tsc -b && vite build --mode lib

vite v8.1.5 building client environment for lib...
✓ 29 modules transformed.
computing gzip size...
dist/paragon-rich-text-editor.css    0.64 kB │ gzip:   0.38 kB
dist/paragon-rich-text-editor.js   888.44 kB │ gzip: 233.36 kB

✓ 29 modules transformed.
computing gzip size...
dist/paragon-rich-text-editor.css        0.64 kB │ gzip:   0.38 kB
dist/paragon-rich-text-editor.umd.cjs  668.45 kB │ gzip: 208.71 kB

That’s not exactly “light weight” considering the limited functionality. But additional functionality shouldn’t bloat the size too much as most of Lexical is already in there.

I did a bit of research on prior-art on this topic and end up from an ADR from 2023 with an interesting comment - docs: add TextEditor ADR by connorhaugh · Pull Request #1131 · openedx/paragon · GitHub

That said, it may be interesting if Paragon one day supported its own custom text editor component that didn’t rely on TinyMCE, but instead something like GitHub - facebook/lexical: Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance. · GitHub.
@adamstankiewicz

So, I thought it might to be a good idea to pose the question to the community. I have a very limited knowledge on the usage of TinyMCE across the the projects. So at this point, it’s just a curious question from me.

My main thesis - having a custom solution that’s built with Paragon UI elements would be light weight and integrate better as a part of the native application instead of an iframe with it’s own styles like TinyMCE.


  1. exemplar blocks are a set of XBlocks whose UI are build using Paragon and React instead of the traditional Django template and jQuery. ↩︎

cc @arbrandes @brian.smith ?

I’m definitely open to the idea of having a standard non-TinyMCE text editor component to use throughout the Open edX platform.

One thing I’d like to note is that I’m open to that component as something that uses Paragon, but I’d prefer to not have the component live in Paragon itself.

In atomic design terms, Paragon feels to me like it should be scoped to the atom/molecule level. I see DataTable as an exception to that rule (it seems more organism-sized to me), and I’ve discussed wanting to spin that out into a separate package before.

A text editor also feels organism-sized, so having it as a separate package for frontend-apps to use seems very reasonable to me.

One thing I’d like to make sure we think through (and consult product on) is how TinyMCE is currently being used in the platform today. Different text boxes using different text editors feels like it could lead to confusing UX very quickly. I’d think this would make the most sense if we were to DEPR the TinyMCE editors and replace them all with a new Paragon-native text editor component.

First of all: the abundance of HTML editors everywhere in our platform is part of the reason we have a ton of XSS issues, some of which are considered “features” rather than bugs.

Personally, I think we need to move to a Markdown-first approach, where we only allow Markdown authoring (optionally with support for very limited, sanitized HTML inline) in most cases, and we treat that as the default option for anywhere we need to implement rich text in the platform. It’s way more secure, way more themeable and consistent, and arguably easier to use than HTML.

So: my own preference would be to add a paragon-markdown-editor that provides rich text WYSIWYG authoring powered by Markdown, with zero risk of XSS. And over time, we can convert more of the platform to that. (e.g. add a new markdown block to replace html as the default “Text” component when authoring courses, and so on).

That said, if we need to have HTML editors in the platform, I like your idea of having one that’s well integrated with Paragon, and definitely +1 for having it as a separate package, and also to extracting DataTable from Paragon core. And for backwards compatibility we definitely need this in a few places at the moment.

Something we were careful about in the Exemplar project was ensuring we ran any rich text field through a strict sanitiser (see sanitise_simple_html()). This was both for avoiding XSS, and for ensuring the html stayed simple and themable. In the frontend we configured the tinymce editors to also provide only a small number of toolbar items to avoid complex html being entered in the first place.

Markdown would definitely be nice. We’d have to be careful to strictly sanitise everything in the backend still to avoid XSS issues, because most markdown specs allow writing inline html as well. Although, how would markdown be different from a strict html subset, if both would be presented as a WYSIWYG editor in the frontend anyway?

Nice.

You’re right that it’s not a huge difference, and maybe a sanitized HTML subset is a simpler evolutionary direction for the platform.

I have a moderate preference for Markdown because:

  • Safety is trivial - just disallow HTML tags in most places, and then be very selective about what you enable via allowlist in others.
  • You cannot have syntax errors in Markdown - at worst, it just renders the Markdown special characters as text. Whereas with HTML, a stray unclosed tag can cause huge sections of content to disappear.
  • Editing the Markdown source is much simpler than editing HTML source
  • Markdown source / plain text is readable, unlike HTML
  • Markdown is arguably more industry standard for this use case these days - LLMs use it as their native rich text format, Discourse/GitHub/Reddit/etc. Obsidian / Apple Notes / etc. Copy-pasting among these various tools works better when you’re not using HTML.