What you see is what you want
We build web sites for our clients and, almost without exception, those sites exist to communicate some content to our clients’ clients. This means that authoring that content is the key interaction our clients have with the software we build for them.¹ We want it to be great and, as developers, we can often choose our own convenience over that of our clients’.
For a long time I advocated Markdown as the ‘best’ solution for the rich-content areas in the sites we built for clients. It allowed people to have some control, but also protected them from the complexities and error-prone nature of writing HTML by hand. And while I love Markdown — I’m writing these words in a Markdown editor — Markdown is not a good solution for non-technical users. It may let them write content, but it doesn’t empower them to author rich and complex things.
We’ve seen people struggle to learn how Markdown worked, had them frustrated by having to learn an obscure syntax, or simply not use it enough to remember how it worked the next time. This is a problem. We build applications for our clients to use. We want to make it easy for them to do the things they want to do. We want them to be delighted by our software, not frustrated by it. What we need is an editing interface that they can intuitively understand, where they can see their changes immediately. In other words a —gasp— WYSIWYG editor.
Why WYSIWYG? The reason is simple: an editor should act like a non-technical user would expect.
- You should be able to copy and paste any sort of content.
- You should be able to select across complex elements.
- You should be able to undo and redo your changes.
- You shouldn’t be able to get into a broken state².
And for a developer:
- You should have complete control over the interface.
- You should have complete control over the data.
WYSIWYG editors have long been the bugbear of developer types, you don’t have to look far to find endless articles proclaiming how WYSIWYG editors will destroy your website. Mostly their arguments boil down to the technical failures of WYSIWYG, not the general user-experience. And while technical failure can obviously affect user experience, it’s hard to argue that Markdown is a better experience than a working WYSIWYG editor for your users.
If I’m honest, I think a not-insignificant part of my soft spot for advocating Markdown was that I was simply overwhelmed by the complexity of the various JavaScript-based WYSIWYG editors. Markdown was simple, safe, understandable. Thankfully, my depth of knowledge has (at least slightly) improved in the intervening years and so has my ambition to create a writing interface that is both intuitive for users and powerful for developers.
Twice now I’ve written complex WYSIWYG editors for various projects, the last a Medium-like interface that powers the authoring interface for the University of Melbourne’s Pursuit platform, and twice now I’ve been left feeling dissatisfied. One effort was built on top of the rather venerable (and unfairly maligned) TinyMCE, and the next on the Guardian’s Scribe project. While the editors work — and they do work well, they’ve enabled our clients to author complex, beautiful content in a data-resilient way — they have this fundamental weakness: they rely on ContentEditable
.
For a primer on the issues surrounding ContentEditable
you should read Nick Santos’ treatise, Why ContentEditable is Terrible. So much of it rings true for me. The model that ContentEditable
provides out of the box is inherently broken. It conflates the visual representation of state with the underlying data model. When you type into a standard ContentEditable
field, you’re editing the visual representation of your data and so you have to reconcile those changes with your data model by parsing them out of the visual representation. When someone pastes in invalid markup, you need to work out how to deal with cleaning up a data store that is already contaminated. This is a recipe for fragility and sadness.
In a heady daze of optimism I even briefly considered writing an editor to solve this problem. Thankfully I procrastinated enough for long enough for there to be an explosion of projects trying to build a great base for rich text editors. Some show great promise, but they’re also a bit rough around the edges in places.
One thing these projects have in common is the same solution to ContentEditable
’s data-confusion: they treat the ContentEditable
element as an input/output device. They intercept any key-presses, translate that change into the data model, and then render that data back to the view. This cycle means changes come through indirectly, giving us a chance to clean/normalise/fix-terrible-Word-html the input before they reach the storage layer for the data.
The most interesting of these new libraries is Facebook’s Draft.js, an editor built on top of React. This makes a lot of sense, as React makes it incredibly easy to avoid the jumble of data and its representation³: data flows in, DOM elements flow out. If you change the data you simply re-render your application and React resolves the differences in the result.
Draft.js is still very new, but you can take some confidence in the fact that it’s used in production at Facebook. It doesn’t give you much, but what it does give you is an API that allows you to build complex interactions without ceding control over your data. For example, there’s no ‘official’ way of getting data in/out of a Draft editor-instance — you’re left to work that out for yourself.
The way you change data in a Draft.js editor is to push new (and immutable) state into the editor instance (though some of the API methods hide this implementation detail from you). And while this seems like a complexity at times, it means you can operate on the data in a functional way. You get to assume the data is “correct” before it gets to you.
The projects in which we’re looking to use an editor already include React, so it makes sense to build on a tool that is consistent with that stack. If an editor that leverages React isn’t your cup of tea then Trix, the open-sourced rich text editor from the Basecamp team might be of interest. I found it wasn’t a fit for our needs as it assumes a lot about how you’re going to use the editor, but they’ve made it very easy to get up and running. If all you’re after is a well-behaving rich text editor however, I would give it a look-see.
We’re just getting started with Draft.js, and I’ve yet to push its capabilities particularly hard, so it’s entirely possible that the next time I write this post there’ll be three editors in my list of WYSIWYG-projects-I’ve-known-and-loved. For now though, I’m excited to be able to build a beautiful writing interface without feeling hamstrung by the underlying technology.
We’ve started open-sourcing a few of the small pieces we’ve been building on top of Draft.js, and I’ll be writing up some of the things I’ve learned about how the editor works as we release more — next up will be a intro to the Draft.js Plugins ecosystem. If you’re looking for help, there are friendly and useful people hanging about in the draft-js Slack, oh, and I’m there too, so say hello.
- Of course a rich text editor isn’t the only part of authoring content, and we’ve been working on some projects to improve the whole process of developing great authoring interfaces. Stayed tuned for details!
- Though if we’re truly replicating the expected *cough* Word *cough* behaviour then perhaps this isn’t a given.
- You can of course get yourself into a terrible mess with React too.