Slate.js: Customizeable rich text library inspired by Draft.js
docs.slatejs.org
docs.slatejs.org
I'm using draft.js in production (at http://www.guilded.gg). I just started looking for a replacement for a few reasons:
1. Draft is pretty broken on Android, despite being marketed as a cross-platform project. The team says that they're not working on fixing it, and it's not trivial to fix. This is a dealbreaker on its own.
2. I've had users encounter bugs where the Draft editor will serialize state that it can't read - so you can save something, and then cannot reload it. It appears to happen when doing some weird combination of adding and deleting block elements. This is a dangerous and frustrating bug.
3. In my opinion, the DraftJS API is difficult to use and extend.
Do you (@author) plan to support Android and iOS? If so, I'll definitely give this a shot.
I'd guess that there are definitely some x-browser issues with Android right now because I haven't tested there at all. So far I've been working on the core pieces of the library, and making sure desktop works. A few folks have contributed iOS fixes for things like autocorrect. I'd love for any contributions that make things work better on Android! (Or other platforms.)
Thanks!
Edit: The landing page of the project does not seem to be optimized well for mobile. When on mobile, make sure to try the editor on http://prosemirror.net/examples/basic instead, as the landing page causes some unwanted scrolling for me on mobile.
Edit: I see now. I've had a look around and this open pr seems to fix it for draftjs:
https://github.com/facebook/draft-js/pull/1013
How are you currently handling Android? We're launching with draftjs in two weeks and need to support Android.
It seems to be a continuation of the issues with the editor state and DOM falling out of sync.
I can't share the implementation project, but this is the issue: https://github.com/facebook/draft-js/issues/1089 And the component: https://robert-fairley.github.io/draftjs-litho-editor/
(my component was never meant for mobile use, though. Built for a desktop web app.)
Slate helps me so much to speed up development. I don't want even to think about working on my wiki app without using Slate. Sure it is still in beta. Nevertheless it is incredible how fast ianstormtaylor reacts to bugs. I haven't found an issue with Slate that couldn't get fixed within a few days.
Great work! Thx so much ianstormtaylor!
I tried it out after becoming frustrated with Draft.js, and it's been a joy to work with. Slate's documentation is excellent, the code is well structured and easy to read, and I love how painless it is to implement custom node types and serializers.
Another thing that irritated me a lot about Draft.js is the fact that Entities can't be applied to the same character in content block. One more reason I had to switch to ProseMirror.
You actually can handle things like "text-align", by adding custom data to nodes, which you can then read back via:
const alignment = node.data.get('alignment')
Where .get(key) can be anything you want.So text alignment would just be deciding on a key/value to use, and then toggling styles in your React component based on the alignment value.
That said, it doesn't handle text alignment "out of the box" if that's what you mean. It doesn't really handle anything out of the box, because you have to opt-in to anything that changes your schema. This is by design though, and it makes it a lot less complicated to use Slate than some of the other frameworks when you start building complex editors. But if you're looking for a drop-in editor that has basic features then Slate is not the right choice.
> it doesn't handle text alignment "out of the box"
That's quite alright. ProseMirror doesn't handle that out of the box too. A lot of new frameworks for rich editors surprisingly don't have that.
function MyNodeComponent(props) {
const { node } = props
const textAlign = node.get('text_align')
return <div style={{ textAlign }} {...props.attributes}>{props.children}</div>
}
Does that work for you? I'd be curious to hear what you mean by "marks but for nodes" and how you were thinking the API would look—sounds interesting!Slate is different than Draft in that it gives you full control over the rendering logic—one of the things that frustrated me when using Draft and that I wanted to solve when creating Slate. It's much more flexible than Draft in that sense.
I haven't really thought much about API or possible implementation for Marks for Nodes. My thoughts generally revolve around the idea that blocks should have extensible styling via Schema in the same way you can add custom Marks in your Schema. You should be able to change styling of the nodes within the Schema instead of overriding block simply because of the alignment or some other minor style.
Since the components are all React components you can use the same types of extending patterns you'd use in React. In this case you'd probably use a higher-order component (HOC) that handles adding to the `style` property based on the node's data. And then you could wrap all of your other blocks with it...
quote_block: alignment(QuoteBlock),
code_block: alignment(CodeBlock),
...
One of the things I started with was making sure that components are just React components, so that all of the patterns that the React ecosystem brings can be used with Slate.There are some bigger architectural things that I'd like to work on, but they're probably best handled by me since lots of context is required. But I've been marking lots of issues as "help please" [1] on GitHub. And other than those, anything marked "bug" [2] would be awesome to get help on too!
[1]: https://github.com/ianstormtaylor/slate/issues?q=is%3Aissue+...
[2]: https://github.com/ianstormtaylor/slate/issues?q=is%3Aissue+...
Just a quick question: is it possible to have text nodes that can't be edited inlined with others editables? I'm thinking of using slate to let users edit specific parts of a legal document (e.g: name, address, DOB, etc). In other words, a WYSIWYG text editor with specific fill in place holders that won't let the user mess with the other parts of the document. Thanks!
Yeah that should be possible, although there might be some weird browser inconsistencies, not totally certain on that. But check out the "Check Lists" example, the checkboxes are actually non-editable content that's rendered right in front of the editable text of the list item.
Than yes - that is certainly a one way to handle it. However this approach would apply a some alignment-related CSS class instead of applying style to the block itself.
Here's what Draft.js would return:
`<p class="align-right">Text Text Text</p>`
I would prefer if it was:
`<p style="text-align:right;">Text Text Text</p>`
1. The scroll region does not follow the cursor.
2. I tried copy+pasting the demo-content a couple of times, and I noticed that the editor gets really slow at relatively small document sizes. Especially "paste" is slow.
Custom document model has its advantages in state change tracking, complex custom elements, unified rendering in different browsers (probably some other reasons too).
https://medium.engineering/why-contenteditable-is-terrible-1...
There are other problems with using contenteditable as well. Copy paste becomes very challenging (you're sanitizing an dom tree and actively snipping stuff you don't want, instead of converting only things you do want into the intermediate representation). As an exercise, look at what an older tinyMCE editbox actually looks like on the inside after you paste something from MSWord.
I have been using quill.js in production for a while now (since well before it was 1.0), and having an internal representation of the text state that gets turned into HTML on the fly as necessary is a good thing. Since rich text editors are by necessity generating user content, I feel less worried about exposing crappy content on the DOM to people who view what was edited - I have total control over what DOM nodes get emitted (the legacy system I replaced allowed for pasting raw HTML, so I'm a little sensitive to this).
Plus, having my content be in an intermediate JSON representation is quite useful. For example: It's trivially easy to wire the source of diffs from quill into a log server for playback, so you can handle concurrent editing without an impossible amount of work. Also, I actually transform the representation differently depending on context. In an email notification, an atMention custom element gets rendered as a boring href with some style, but internally to the site, an atMention gets some custom element stuff that allows a flyover to show the user. This would be a lot harder if I didn't have control over the json -> html transformation at render time.
https://medium.engineering/why-contenteditable-is-terrible-1...
HTML offers a number of advantages over a custom json-based document module, not the least of which is interop. You'd never want to store Skates data model in a database in case you switch editors.
I also agree, though, that this leads to some degree of lock-in. You'd have to write a transformer to convert to your new framework, but that's not particularly hard.
Ultimately, though, the way I think about it is: react, angular, ember, vue all work by converting a JSON representation of state into a dom tree. So, an editor doesn't really need to be much different, as long as render times are fast, having an internal representation that's projected on to the DOM is a pretty common pattern.
In particular, the moment you have content (data) that doesn't map 1:1 to DOM, you have an issue. For example, imagine I want to embed a "photo object". It's not just an image; it also renders the photo credit/copyright underneath. But that makes it a composite; internally, it's a photo ID, the dimensions, maybe some cropping info, plus the crediting metadata. So the internal data node no longer maps directly to the DOM. Internally, you want a single node, but in the DOM it would have to be multiple when rendered.
Same goes for other composite embeds like videos, maps, forms, tables and so on.
Editors are classic MVC: Regardless of whether the view is HTML, Cocoa, Qt, whatever the Windows UI API is these days -- you need to keep model decoupled from it.
1) Can this be used as as content-editable substitute? 2) What format is the marked-up text stored in, and does it require Slate to be rendered?
1) It depends on what you mean by substitute. It's kind of like a contenteditable that's been implemented with React components and an Immutable.js data model. It's not a drop-in replacement for contenteditable, since the APIs are different. But that is essentially what it lets you do.
2) The data is stored internally in an Immutable.js tree data model. You can convert it to JSON with the built-in `Raw` serializer. And you can define a schema with the `Html` serializer to convert it to HTML, which then you could render anywhere you want. I do this for one of my projects.
Thanks for clarifying the data model & serializers.
Still, I'm keen to give it a go.
I had originally started with just the few I'd used or researched in the initial stages. But folks opened issues in Slate asking for more comparisons, so I tacked on other libraries that people were interested in comparing. But I should really move those other libraries to another page in the docs somewhere with a better disclaimer.
[1] http://code.weflex.org/markdown-editor-flavored/ [2] https://www.npmjs.com/package/markdown-editor-flavored