contentEditable attribute to
true on an HTML element, make use of the non-standard but commonly-implemented
Until next week that is, when your product owner adds a few small items to the backlog: can we please add a button? We want to insert images and emojis; our clients in Europe would like to write their content in Finnish; make it work with a screen reader; and keyboard navigation. On all browsers and mobile devices.
You: 😱 😱 😱
Soon, you are falling down the rabbit hole of writing your own rich text editor. The great
contentEditable paradox is that while it is easy to do the trivial, it is near impossible to do anything else.
“I don’t need a whole library. I can probably write it myself”
When you load a whole library for some code you could probably write yourself pic.twitter.com/803ical88x— Sarah Drasner (@sarah_edo) February 6, 2018
contentEditable attribute specifies whether the content of an element is editable or not. When the
contentEditable attribute is not set on an element, the element will inherit it from its parent. For example,
<p contenteditable="true">Type here to change words</p>;
creates a paragraph element whose text can be changed after the HTML page renders. The content will only be changed locally in the user’s browser, so some further action will be needed to save any changes made.
The ease of getting started with
contentEditable has led to many partial editors including the Yahoo! UI (YUI) editor, the many JQuery editor plugins, the Aloha editor, and a number of other projects that have lost steam within a few years. Even well-resourced teams like WordPress and Medium have invested years of effort, and at times walked away from multi-year developments after hitting an impasse.
In most cases, this impasse is caused by the complexity of delivering an editor that is robust and full-featured. Robustness and feature delivery are really, really, hard to achieve largely because of the inconsistencies in the way that browser vendors implement
As there are no standards on the implementation of
contentEditable in the browser, each vendor is free to implement it, and change it, as they wish. From small differences, such as how events like pressing
[Enter] get encoded in the HTML representation (will it be
<br>?), to more nuanced issues like browser selection models – the problems quickly reach levels of complexity that make them expensive to resolve. They, in turn, affect the robustness of your editing solution.
While discussions on extending and standardizing the implementation of
contentEditable are taking place at the World Wide Web Consortium’s Editing Task Force, progress is slow. For now, building your own editor means accepting that the HTML representation of your document will be different depending on which browser was used to create the content. This limitation generally makes home-grown editor solutions fall short.
If I don’t write my own, which one should I choose?
Web-based rich text editors generally fall into two camps: those based on
contentEditable, and those based on a virtual DOM. If you are looking to make a reduced feature editor that works in a subset of browsers, you can get things going fast by coding your own editor. The more complex your feature set, and the more important capabilities such as internationalization, accessibility, cross-browser and cross-device performance are, the easier it is (in the long run) to use an editor based on
contentEditable. We have a handy diagram showing these trade-offs:
Editors such as TinyMCE, Textbox.io and Froala protect the developer from browser differences by implementing a consistent layer on top of
contentEditable. There is a significant up-front investment in development effort required to re-implement many of the “basic” events to behave consistently, for example, handling of the
Enter key and text selection. It is easy to overlook the thousands of development hours that have gone into making these basic features behave consistently in different browsers.
The alternate approach to using the
contentEditable model is to re-implement all the input and interactions using a custom virtual DOM. The virtual DOM represents a conceptual abstraction of the document, which is then serialized back to each browser separately. Techniques like operational transforms can be used to transform the model, and change the document state. Unfortunately, the limitations of techniques such as operational transforms on complex data structures like nested tables make it difficult to implement complex requirements such as nested tables and lists, proper internationalization (including right-to-left text) and accessibility. On the plus side, this approach calls for much less development effort up-front, making it a great choice for editors with a fixed set of requirements.
With mobile consumption of content overtaking the desktop, it is likely that mobile content creation capabilities are already in your feature backlog. Unfortunately, the
contentEditable approach is fraught with potholes when it comes to creating a mobile-enabled rich text editor. For a time, Google made inroads with early versions of their browser-based Google Docs mobile editor, but abandoned the attempt when they hit unresolvable issues with flashing content and keeping the cursor on the screen. Instead, Google created native applications for mobile platforms. At Ephox, we have (miraculously) created good mobile editors for both TinyMCE and Textbox.io, but it has been seriously challenging.
The virtual DOM approach relies on the detection of input events, including key events, which are non-trivial on mobile devices. To our knowledge, this approach is largely untested in mobile applications. However, this space changes every day so if you know more than us please let us know in the comments below 👇.
An end to editable discontent
Choosing a rich-text editor for your application, or choosing to write your own, has many trade-offs. There are a lot of great alternatives, and aesthetics aside, when you examine the core structure of different editors, each product is based on a slightly different approaches with different tradeoffs.
The TinyMCE team continues to invest in the
contentEditable approach, and with it the promise of robustness and feature completion. Our goal is a high-quality, complete and stable API on top of
Since TinyMCE was launched, we have seen many new editor libraries emerge. The competition has helped us to continue to look ahead, to redesign many user interactions, and to create some awesome premium features and capabilities (like cognitive integrations, and talking bots). We deliver the new on top of the robust and trusted TinyMCE Core rich text editing framework, ensuring that we don’t compromise reliability in the pursuit of the new and shiny future. We are modernizing the TinyMCE Core progressively and in a step-by-step and API-compatible way. For example, we have recently migrated to TypeScript in the Core.
2018 is going to be an exciting year for us as we ramp up for the delivery of version 5 and continue to make Tiny the biggest thing in rich-text editing. Stay tuned!
This post was written with the extensive assistance of the amazing engineers on the TinyMCE and Textbox.io teams in Brisbane, Australia. A big thank you to Morgan Smith, Ryan Pollard, Damien Fitzpatrick and David Wood for their help 🙌.