Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Slate.js: Customizeable rich text library inspired by Draft.js (slatejs.org)
228 points by malloryerik on April 16, 2017 | hide | past | favorite | 69 comments


Ooh, this looks very promising. Nice work.

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.


Have a look at ProseMirror (http://prosemirror.net). It works quite well on Android and iOS and the maintainer is super responsive and has already fixed a lot of Android/iOS specific issues.

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.


In what way is Draft broken on Android?

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.


On Android there is a high chance your text won't appear, or the keyboard will disappear. Trying to delete text will cause the cursor to jump around if you hold delete down instead of one character at a time. Very frustrating.


The cursor and atomic block deletion issues occur on desktop as well. I filed an issue recently on this very thing.

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.)


Just tested...doesn't work on my Android Chrome browser right now but hopefully it gets there.


Yeah, I just did some testing on an Android device as well and had the same result. I like Slate's API and data model more than Draft's, so I'd almost certainly switch if this were fixed.


Hey, author here, good question!

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!


I am using Slate for a few months now. Before that we used Quilljs and looked also at other editors before switching to Slate.

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!


Slate is really fantastic.

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.


Seems fairly similar to Daft.js including one of the issues that stopped me from using Draft.js - lack of ability to stylize root Nodes specifically inability to add "text-align" style to paragraphs. Sure, there are some workarounds for that, but those are just terrible hacks bolted on top of the inflexible model system. I had to switch to ProseMirror where that was easier to implement.

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.


Hey, Slate author here. I didn't realize this was going to get submitted to HN, Slate's still in beta but it's fairly production-ready.

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's been several months since I used Draft, but if I remember correctly some of the editors based on Draft use same approach with defining custom data on the node and then applying custom class with assignment (for example you end up with: `<p class="align-right">Text Text Text</p>`). Too hacky for me. I would have loved if Nodes had native style suppord. Kind of like a Mark but applied to the whole root node instead of character ranges.

> 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.


You can actually choose to use styles instead of classes fairly easily too. Since it's all defined in your custom React component you can do whatever you want, for example it would be written as....:

    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.


That does indeed work. You do need to override Node component and if you want to have even more changes - all of those would have to be located within that custom component.

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.


That makes sense. And you can do that with Slate!

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.


Slate looks outstanding. I stopped work on my own lib when ProseMirror came out, but since then I've found that it and Draft.js still don't meet my needs. How can I contribute to Slate? What do you need help with?


Thanks! :D

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+...


Hey, thank you for sharing! The docs are amazing and very easy to understand.

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!


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.


Thank you very much for replying and pointing me to the right direction.


hey, could slate be used in an ember.js project or is it only for React? or do I need to install a react component inside ember to use this?


It's been a few years since I worked on Draft, but can't you just define a custom block style to implement alignment?


If you mean Block Styling like here: https://draftjs.org/docs/advanced-topics-block-styling.html#...

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>`


I just tried the example, and two things I noticed:

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.


I wish these libraries didn't invent their own document model when we already have HTML. Just let me edit HTML, within constraints setup by a schema, and allow extensibility of the document via HTML custom elements.


As other people mention, you can't really do this effectively via contenteditable, as user-intent (make that line bold) isn't uniformly transformed into consistent DOM across browsers. Medium had a great post about all that a couple years back. They wouldn't go through the trouble of re-implementing contenteditable if it weren't absolutely necessary.

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.


Here's that Medium post: Why Content Editable is Terrible

https://medium.engineering/why-contenteditable-is-terrible-1...


Who said anything about contenteditable or not having control over the content? The editor can have complete control and still store the document in markup rather than JSON.

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 agree that HTML format has some strengths, but if you're working with data in javascript, there's a lot of strengths to a json format as well. Personally, I do store json data in my database (in a jsonb postgres column, which gives me some query capabilities that aren't necessarily available operating on html strings in the database).

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.


HTML or any other markup language for that matter is very hard to translate into a well-defined and predictable data structure. When working with content editors, this, to me at least, is a hard requirement.


In addition to what the other commenters said: HTML/DOM is a presentation-oriented document model. It's the "V" in MVC. It only works as the data model for something that is analogous to HTML.

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.


You could allways use TinyMCE if simple HTML editing is all you need.

Custom document model has its advantages in state change tracking, complex custom elements, unified rendering in different browsers (probably some other reasons too).


You can do all of that in HTML, especially complex custom elements that render the same in all browsers.


but you can't do all of that in contenteditable... that's the point.


I'm not taking about contenteditable, but the document model of the editor. Markup is much well suited to rich text because that's exactly what it was designed for.


Then you have to handle cleverness around cursor highlighting, cross platform keyboard shortcuts, copying and pasting of rich text... why not start with a decent base of functionality with contenteditable inputs?


I don't understand what you're saying. Rendering the UI of the editor should be independent of rendering the content. contenteditable lends itself to an HTML document model anyway.


The markup that's generated by browsers in rich text areas is not standardized. Sort of a deal breaker for cross platform compatibility.


Theres also good article from Medium's engineering titled "Why ContentEditable is terrible":

https://medium.engineering/why-contenteditable-is-terrible-1...


As Rosenhai mentioned, you can use any 'old' editor like Summernote or TinyMCE if you just want to edit html. The problem comes when you want to sync changes to server / others in collaborative environment. Without a state, all you see is a dom element and then you have to generate the diff which is pretty hard due to browser nuances.


I'm with you on not reinventing DOM, but often you don't want your Document Model tied to DOM - despite nominal similarities - and Slate seems like a good example of how simple things can be made, even for rich document/app type things.


You might like SGML, the ISO-standardized markup meta-language on which HTML was built originally. In my project ([1]) I'm trying to bring it back to the web.

[1]: http://sgmljs.net/blog/blog1701.html


Would it be possible to do live collaborative editing with a pure html-as-data model? One nice thing about Slate.js is that it leaves the door open to high-quality collaborative editing in React.


Anyone wanting to look at Github, this is the link https://github.com/ianstormtaylor/slate


Wow this looks really great. I've been building something with Draft.js + plugins and I can already see how this will make my vision easier to implement.


Two probably dumb questions, but I can't tell from looking at the examples and a brief scan of the docs:

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?


Not dumb! (Author here.)

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.


By "substitute" (poor choice of words), I meant - can this be used to allow live editing of parts of page, with their layout and formatting intact?

Thanks for clarifying the data model & serializers.


Does slate.js use contenteditable as an underlying primitive?


Yes. (That much I figured out). :-)


Thanks. Do you know why? If I had to write a text editor, I would not build it on top of something as unreliable (across browsers) as contenteditable. But I'm sure there is a good reason for it.


Yay, inline markdown with applied styles. I'm missing that from most markdown editors. Sadly missing images and no real html output that I could apply my css on.


I plan to use slate or draft to write MathJAX or ASCIIMaths writing. Can anyone suggest which one will be more better to write MathJAX or ASCIIMaths?


How hard (or easy) is it to implement mentions?


Looks like this plugin will help https://www.npmjs.com/package/slate-suggestions


The author mentions issues with a lot of editors he's not actually used, which I find a bit odd.

Still, I'm keen to give it a go.


Agreed! (Author here.)

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.


How is the performance when rendering many read-only copies, e.g. for comments? I believe draftjs is quite poor.


I get a 404 error for all of the examples.


Ah sorry about that. I'm the author of Slate, but I didn't submit this story or else I probably would have linked to the GitHub page itself. Fixing now!


Ah, I submitted this, late last night (in my timezone), because I was happy to have stumbled across it on my quest for a highly-flexible rich text editor in React. Maybe I should have contacted you first. I linked to the docs because they're so clear and well made, and thought that might have been overlooked if I'd linked to slatejs.org. Hacker News search told me that the GitHub repo had been submitted twice in the past, with no results. Waking up I see that I even misspelled customizable... Sorry about that ^_^


No worries!! I should have fixed the intro docs page haha. I'm glad you like it and thanks for submitting!


Try accessing them via Github. Here's the URL for the comprehensive live demo: http://slatejs.org/#/rich-text?_k=emqwxj


Slightly off topic but does anyone happen to know if GitHub's markdown editor is open source?


I have been looking around for awhile for it. I found something that is inspired and looks pretty accurate.

[1] http://code.weflex.org/markdown-editor-flavored/ [2] https://www.npmjs.com/package/markdown-editor-flavored


For people that don't know React. You got documentation in plain old js?


All the example links broken, and show 404 not found


I hate when pages break the back button on mobile




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: