top | item 11153757

Draft.js – Rich Text Editor Framework for React

592 points| tilt | 10 years ago |facebook.github.io | reply

112 comments

order
[+] marijn|10 years ago|reply
My ProseMirror [1] project is in the same space (including using persistent data model detached from the DOM). It has a richer, tree-shaped document model and collaboration [2], but not quite as much programmerpower behind it since I'm a single OSS dev as opposed to a giant tech company.

[1]: https://prosemirror.net [2]: http://marijnhaverbeke.nl/blog/collaborative-editing.html

[+] JohnHammersley|10 years ago|reply
Just wanted to take this opportunity to say thanks again for CodeMirror, and it's great to see the progress you've been making with ProseMirror.

We use CM at Overleaf[1], and it's been fantastic. To make it easier for non-LaTeX users to collaborate on LaTeX documents, we built our own rich text editor on top of it[2], which is still in beta. Still got a long way to go!

[1] https://www.overleaf.com

[2] https://www.overleaf.com/blog/81

[+] nsfmc|10 years ago|reply
ProseMirror is great. A few months back i was looking for a rich text editor for use in an isomorphic js webapp that uses react. I probably spent more time researching and testing out other libraries than i did getting prosemirror working in our app (and even ended up even contributing back some code in the process). Highly recommended, i think for most cases, prosemirror strikes a good balance between sensible defaults and easy integration.

Where it falls down is mostly in documentation, which is 100% understandable, since it was crowdfunded(!), but the code is very legible and amenable to most kinds of webapps.

Where i suspect draft.js probably shines is having tighter client/data boundaries and code that natively expects to be rendered isomorphically, so calls to window/document are probably more tightly managed given that the whole view layer uses react and likely expects to be rendered on the server.

That said, ProseMirror has a 100% fantastic "give me the current ast rendered as markdown" which, in my case at least, was the thing i wanted the most and that ProseMirror supplied handily. Draft.js will have you roll your own[1], but at least the draft.js api is fairly friendly.

There's obviously more than enough room for both projects, but i think that for react based projects, draft.js will feel like a more natural fit even if it will take more effort in the short term until more functionality builds up around it.

[1]: https://github.com/facebook/draft-js/blob/06891490069d3ccfb8...

[+] vanderZwan|10 years ago|reply
> I'm a single OSS dev as opposed to a giant tech company.

Yes, but you are Marijn Haverbeke and they are not. I have more faith in your ability to make good decisions than I have in any giant tech company, TBH.

[+] leeoniya|10 years ago|reply
FWIW, i always use Codemirror as an agument against DSL-specific, locked in components. While declarative React components are "reusable" they're only "reusable [within React]".

Imperative components with APIs is where real reusability exists. Case in point: React can consume them but cannot create them for external consumption.

EDIT: I hate to make this reply self-serving, but this is exactly why domvm [1] now exists. It promotes imperative components with declarative OR imperative view/subview composition. It slots firmly in between Mithril and pure-vdom frameworks, removing structural enforcement and avoiding promotion of a specific MV* paradigm. It's among the most performant vdom implementations to boot.

[1] https://github.com/leeoniya/domvm

[+] shaneos|10 years ago|reply
It's worth clarifying that Isaac, the engineer behind Draft.js, also basically built the entire thing himself. He did it inside a large company of course, but it was his labour of love for a long, long time.

This is the type of cool stuff you get to work on at Facebook, come work with us :-)

[+] tomp|10 years ago|reply
Hi! Your project is amazing, as is CodeMirror. A few months ago, I was looking for an editor for a personal blog/notebook. I'm a programmer and I often want to write down ideas about programming languages, so I wanted an editor that would combine WYSIWYG with a syntax-highlighting code editor. After a lot of effort, I managed to embed CodeMirror into the CKEditor, with almost seamless editing without any modal windows. Since you're the author of both a code editor and a WYSIWYG editor, it would probably be easier for you to implement this kind of functionality, which would be really amazing for many use cases!
[+] yesbabyyes|10 years ago|reply
I have recently implemented ProseMirror for a client and added some functionality using the API and I can only say good things about this editor. It is everything I have been looking for in an embedded rich text editor for the web and I am thrilled to follow, and hope to be a part of, it's future development!
[+] fibo|10 years ago|reply
Seems a valid project, I added it to the list of editors with ace and draft.js (thanks for sharing :)
[+] grayrest|10 years ago|reply
Do you want contributions? I've done a cursory check of the repo a couple times but my use thus far has been fairly low key and I haven't run into errors for bug reports and most of the stuff on your roadmap from last fall the sort of conceptual / organization work where outside contribution isn't particularly helpful.
[+] vanderZwan|10 years ago|reply
> But you can save oh so much complexity by introducing a central point. I am, to be honest, extremely bewildered by Google's decision to use OT for their Google Docs—a centralized system.

Could a reason be that Google Docs allows for offline editing (if you install the Chrome extension), making it easier to save all these changes at once when an internet connection returns? You mention later that OT doesn't help when trying to merge conflicting edits (in which case Google Docs will spawn a "<collaborator>'s conflicting copy of <document name>", IIRC). However, if this level of conflicting desynchronisation is rare, and if OT makes it easy to push large changes after editing the document offline for a while, they might have decided it was worth it.

[+] bantic|10 years ago|reply
(biased author of Mobiledoc-Kit here)

The past year or so has really seen a resurgence of browser-based text editors. Off the top of my head I can think of 4 editors/editor-frameworks launched in the past year (Mobiledoc-Kit, ProseMirror, Trix, and now Draft.js). Browsers are creeping toward exposing all the events that are necessary for interpreting the meaning of a user as they input text. (Some notable exceptions remain, such as an event that would be fired when a spelling correction is accepted, but mutation observers provide a fallback for cases where it's not otherwise possible to catch the input on the way in.)

A major focus of Mobiledoc-Kit, which seems to have some overlap with Draft.js, is on exposing an API that allows programmers to programmatically interact with the internal (structured) document. Our goal is to allow developers to be able to construct editors that fit snugly fit their use case, whether that's building their own UI for a toolbar, or more complex procedural rules for document (e.g., add a constraint that there can only be one "H1" section in a document and disallow adding a second one).

Since Mobiledoc-Kit was built for a publisher originally (Bustle), the ability to intersperse text with richer content was a goal from the start. So it has a "card" concept that allows adding any rich content (embedded tweets, videos, slidehows, etc.). In fact, the Mobiledoc-Kit demo page [1] has a demo where a Codemirror editor is embedded inside the Mobiledoc editor.

It's great to see so much new energy in the browser editor world. I am hopeful that as browser features and new editors and editor features converge, we'll see some exciting new developments that broaden the perspective on what sort of content is possible to author from within a web page.

[1]: https://bustlelabs.github.io/mobiledoc-kit/demo/

[+] tomdale|10 years ago|reply
For those of you looking for a rich text editor like this that is lighterweight and doesn't come with a heavy React dependency, I can highly recommend Mobiledoc[1]. I've been using it in several production sites and it has performed like a champ.

The best part of Mobiledoc is its portability; I've seen it used in both Ember.js and Riot.js, two libraries on opposite ends of the spectrum.

It's also been designed for rich, interactive content in addition to rich text. You can add interactive cards (think slideshows, before/after image sliders, etc.) and easily provide a different implementation on each platform. This lets your content authors write once and have a great experience on both native and web, and adding a new card is super easy.

1: https://github.com/bustlelabs/mobiledoc-kit

[+] mixonic|10 years ago|reply
(Mobiledoc contrib here)

One thing Draft and Mobiledoc seem to have in common is a robust programmatic API. Draft is pitched as a "framework for building rich text editors in React". Mobiledoc pitches itself as a toolkit for building WYSIWYG editors, so fairly similar goals.

Mobiledoc is designed to be very quick and easy to render, and additionally to support rich content "cards" and "atoms". These are runtime-implemented rich content sections, and our main sponsor for this work (Bustle Labs) uses them for image sliders, animated and interactive SVG features, videos, and more.

These runtime rendering points also make it easy to have multiple representations of a document. For example, we render Mobiledoc into text for ElasticSearch, into HTML for normal web visitors, and into AMP HTML. When rendering into text or AMP we can't use the normal card implementations, and runtime-configuration makes this easy.

And the rich cards work with copy paste! and undo/redo! Anyway, there is definitely overlap here, but IMO the goals of Draft are pretty narrow so far.

[+] yoran|10 years ago|reply
+1 on mobiledoc-kit. We switched from a custom, hard to maintain and full of browser-specific quirks rich-text editor to mobiledoc-kit about 3 months ago. It's a world of difference in terms of stability and maintenance. It's still under heavy development but it's improving quickly and we're very happy with our choice so far. Kudos to the 201 Created team for this!
[+] ef4|10 years ago|reply
The thing that impressed me most about MobileDoc is how nice the copy/paste support is. You can paste in all kinds of rich content and it does the right thing -- both your own custom cards, and arbitrary HTML gets cleaned up to match only what's allowed in your mobiledoc.
[+] leeoniya|10 years ago|reply
Is there a specific benefit to having this built on top of React rather than just wrapping an existing editor's API [1][2][3]? Is it cross-usability for React-native or just NIH syndrome?

I'm not sure how I feel about re-implementing all the things and introducing a React dependency to everything. The lock-in seems okay if React really is the final word in UI frameworks (though it is very large and currently very slow). I am certainly not in this camp, however.

[1] https://github.com/neilj/Squire

[2] https://github.com/quilljs/quill

[3] https://github.com/zenoamaro/react-quill

[+] spicyj|10 years ago|reply
(Biased React dev here.)

The key insight in Draft.js is that it's incredibly difficult to keep your model in sync with the browser's contenteditable behavior unless you intercept many of the behaviors and perform them entirely in the model, then change the DOM accordingly. Medium found the same thing when building their editor:

https://medium.com/medium-eng/why-contenteditable-is-terribl...

In order to build high-quality text editors, you need to be in control of what's happening in the DOM. There's obviously many ways to control the DOM. React is a solid base for this, as are many other libraries. Facebook uses React extensively so it made sense to use as a base for Draft to avoid needing to essentially rewrite React and to make it even easier to integrate with existing React apps. Of course, you can also use Draft easily inside a non-React app.

The entire Draft model is also separate code decoupled from the UI and you're free to use the model and implement the views yourself if you're allergic to React or aren't targeting the DOM. The Facebook Groups app uses Draft's model but implements custom views for it in React Native.

[+] underwater|10 years ago|reply
In most rich text editors the DOM is the source of truth and the editor reads and attempts to sanitize HTML when you're done.

Draft.JS is a controlled input. The view is completely derived from the model. This eliminates whole classes of browser and editor bugs.

It's also makes the editor really easy to extend. You can add new object types and complex styling without having to worry about all the nuances of text editing.

For example you could highlight hashtags by giving the editor a regex to match and then tell it which styles your hashtag should be decorated with. Draft.js handles creating and removing tags as you type, drag and drop, copy, paste, etc.

[+] jonknee|10 years ago|reply
On the other hand it's perfect if you have a React project and need rich text editing.
[+] terda12|10 years ago|reply
Yes, it's much simpler to have a natively React text editor, that way you can plug in the state of the <Draft> component into your other React components. See http://facebook.github.io/draft-js/docs/overview.html#conten..., everything is nice and neat.

I'm not sure about 3rd party js text editors, but I'm guessing it could be a pain to work with state and props in that context.

[+] iandanforth|10 years ago|reply
Neat, but. I once had to do extensive testing of a rich text editor and know where the most bugs were? un-ordered lists. The world has been trained to expect a very specific set of behavior from bulleted lists by MS Word and it's really tricky to emulate. Specifically, how do tab and shift-tab modify the list? If you have an indented bullet, and hit return from the end of the line, what happens? What if the previous line was bold? What if I select most of two lines and hit delete?

Their demo falls far short of expected functionality which makes me think that there is a huge amount of work to go from this library to a working editor.

[+] bshimmin|10 years ago|reply
The docs do mention nested lists (http://facebook.github.io/draft-js/docs/advanced-topics-nest...) but this doesn't seem to work for me in the demo.

I agree that lists in web-based rich text editors, versus the de facto standard of Word, are a major problem, and I suspect they fall into that "unglamorous" area of development that people don't want to delve too deeply into.

[+] sime|10 years ago|reply
The docs discuss lists and reference Facebook Notes which uses Draft. The demo doesn't support the nested lists but Notes does. I've tried it out and it supports tab and shift-tab. The only limitation seems to be that you can't select multiple items and indent them together - it has to be one at a time. I'm unsure if that's a limitation of Draft though.
[+] spicyj|10 years ago|reply
If you could file issues for behavior issues you notice, that would be valuable and help everyone who ends up using the editor.
[+] amelius|10 years ago|reply
Some bugs found after quick testing:

- When adding a long paragraph, and hitting enter in between, the caret disappears from the screen.

- When typing some text, say "abc", followed by a large number of spaces, and then selecting everything, the selection extends past the width of the editor window (colored selection bar sticks out).

- In a long paragraph, changing to a code-block, again the caret disappears.

More seriously:

- In a paragraph of 10,000 words, the editor becomes really slow, even when just typing text. This is strange because such operations (i.e., typing) are local, and React is supposed to deal only with incremental changes. I'm wondering what is going on here.

[+] true_religion|10 years ago|reply
> In a paragraph of 10,000 words, the editor becomes really slow

I think it's because typing a single character causes it to reparse the entire typed text in order to check if the document model needs updating.

I've seen something similar in other editors. The only solution I can naively think of is to chunk the document and only do checks within the chunk.

[+] tiglionabbit|10 years ago|reply
Oh hey, this looks a lot like something I was working on.

https://github.com/nickretallack/richer

React makes it easy to do a stateless transformation from your data model to some output, so you can model things the way you want to: as a series of overlays onto the text.

My project uses the Google Drive Realtime API as its data model, so you can collaborate on the text too. Or use the in-memory version to edit alone.

I never finished this thing. Was hoping to use it on a project at work, but got shot down. Emulating cursor movements without a text area was the fiddliest part. But I got pretty far into it as a proof of concept at least. I was impressed at how fast it was despite being a JavaScript emulation of content editable.

[+] smrtinsert|10 years ago|reply
I've been targeting Google Drive as well for various document options. It's basically a free cms.
[+] jstejada|10 years ago|reply
This is really awesome-- At Nylas we've /also/ been building one for the past year to use in our email composer inside N1 (https://githbub.com/nylas/n1), with the additional constraint that it needs to support extension by third party plugins.

Building a nice declarative editing interface around an inherently mutable structure with an imperative API like the DOM (which can mutate state from under you, like focus) is a real challenge. Props to the team at facebook for this.

[+] mhodgson|10 years ago|reply
Looks like a nice entrant to the space. React is very well suited to this problem space and they clearly understand many of the pitfalls and problems.

A few questions/concerns:

1. It doesn't look like the undo/redo state is global to the page. The built in undo/redo stack in browsers is global to the page so this is the expectation users will have. If you use multiple instances of Draft.js in your page they will each have their own stack, which is less than ideal. I realize having a singleton to manage this across all editor instances is more difficult in the React/Flux paradigm, but it would be much better from a user experience perspective. Related to this:

2. I don't think you can nest Draft.js instances. There are a number of simple cases where you might want to do this (e.g. custom block with image + caption). To support this in the future it seems you would need to account for it in the selection and undo/redo stack state handling.

3. The data format has a lot of repetition in how it stores inline styles[1]. I'm interested to know why they chose to represent the data this way instead of using indices. For instance, you can represent a inline bold style with a json object like so: {type: 'BOLD', startOffset: 5, endOffset: 10}. The format they chose to use is easier to render directly, but more difficult to parse visually and less space efficient (except in the case of styles that only cover a few characters).

Finally, it seems most modern WYSIWYG editors mentioned in the comments here were at least partially influenced by the original Medium post "Why ContentEditable is Terrible"[2]. It would be great for the community to standardize on a data model/format that could be used in all of these editors. There are enough commonalities (blocks, elements, etc.) that I believe we could create a common document spec that would be usable in all of these popular editors. The benefit of this would be having a common spec to build additional libraries for diffing, server rendering, native mobile editing, and so on.

[1] http://facebook.github.io/draft-js/docs/advanced-topics-inli... [2] https://medium.com/medium-eng/why-contenteditable-is-terribl...

[+] pfooti|10 years ago|reply
This looks pretty neat, although I'm leery of the react.js dependencies as I don't do a lot of react development. I'm sure I could wrap it up or something if needs be. There's a lot to be said for this new move in third-generation rich text editors to move away from relying on contenteditable and the DOM as the source of state. A lot of different projects are doing this becuase contenteditable is clearly not a great solution.

Still, am I missing any kind of delta event emitter? I'd like to be able to hook edit events and push operational transform content over the wire to support collaborative editing. Other projects like ProseMirror, Quill.js and maybe Mobiledoc support this (I haven't used mobiledoc yet, but it looks like that's going to be supported Soon).

[+] nthnb|10 years ago|reply
I've tried to work with a number of WYSIWYG editors and they always get you part of the way before becoming a real pain. No one seems to do a very good job planning them out and maintaining them. I, for one, am really happy to see Facebook release something. Knowing Isaac I suspect this is some work related to Facebook Notes which is cool because it means they're using it in the wild.
[+] hokkos|10 years ago|reply
Great but no support for tables, I can't use it for now :(

So I use CKEditor because it support everything the client want but it is like a trade with the devil. It is the worst js lib I ever had the displeasure to use, it made one developer never want to be on my project again. I needed to fix its sources, and have the non uglyfied code load in my app to debug it, because they only distribute working minimised merged js, I had to make the full sources load in webpack : pack all the js and load de dependancies in order following a config js file. The code is full of ridiculous timeout making the code unfollowable. Never use CKEditor !

I will gladly switch once it support tables.

[+] swax|10 years ago|reply
Same here. CKEditor is extremely feature rich. All other editors feel like demos compared to it. And my customers want/use most of the CKEditor features - embedding images, access to edit the source code, tables, pasting in from MS Word, special symbol lookup, etc.. etc..
[+] fredck|10 years ago|reply
It's curious to see that many pet projects are going public at the same time, all having the same goal of bringing control over the contenteditable madness through a custom data model.

We at CKEditor are going in that exact same direction [1]. We are making a strong switch to the project, wishing to make it a powerful editing framework, just like Draft.js but in a larger scale.

[1]: https://medium.com/content-uneditable/ckeditor-5-the-future-...

[+] swah|10 years ago|reply
By the way, did Facebook ever wrote why they only allow plain text? Its easy to imagine but I wonder if they ever A/B tested it.
[+] harel|10 years ago|reply
Remember MySpace? That's why. When they allow styling of the content by users, it turns into a style war and horrible horrendous terribly bad user experience
[+] thewhitetulip|10 years ago|reply
Does it support github flavoured markdown? Or can we make it support it?
[+] HappyTypist|10 years ago|reply
Bugged on Firefox for Android - typing overwrites what you typed before.