โ† Back to list

Slate.js + dnd-kit = ๐Ÿ”ฅ. Improving Rich Text Editor UX by adding Drag and Drop.

Sometimes writing experience may be improved by having the possibility to reorder content blocks. Tools like notion and note taking appsโ€ฆ

devterminal ยท 2022-06-04 18:25 ยท 12 claps ยท 3.4 min read
#javascript #react #slatejs #dndkit #rich-text-editor
Open on Medium โ†—
Wiki topics: RAG ยท RAG & Retrieval ๐ŸŒ ยท Web Development โฑ๏ธ ยท Productivity

Slate.js + dnd-kit = ๐Ÿ”ฅ. Improving Rich Text Editor UX by adding Drag and Drop.

Sometimes writing experience may be improved by having the possibility to reorder content blocks. Tools like notion and note taking apps have set this trend. I, personally, like this feature especially when I work with lists.

Slate.js and Dnd Kit Preview

Slate.js and Dnd Kit Preview

In this post I want to share an idea on how to inject dnd-kit toolkit into Rich Text Editor based on slate.js.

Code that you will see in examples here doesnโ€™t work as it is. It just illustrates the main ideas. However, working examples in codesandbox are provided.

I tried to keep only necessary information without getting deep into details.

Letโ€™s start!

slate.js

Slate.js is a great framework for building your own rich text editors. You can read about use cases on their documentation page: https://docs.slatejs.org/.

For the really first and simple version of editor we need the following components: Slate, Editable and DefaultElement.

  • Slate component is more like a react context that provides value, editor instance and some other useful things.
  • Editable component renders all nodes and provides right properties to them.
  • DefaultElement is a simple div or span element with applied properties that renderElement receives (attributes, children, element).

The following code should explain how it works in just a few lines of code:

[embed]Slate.js CodeExample

sandbox: https://codesandbox.io/s/slate-kv6g4u

deps: yarn add slate slate-react

I want to share some details about how slate works that are important for current topic:

  • Slate value has Descendant[] type.
  • type Descendant = Element | Text.
  • Element

[embed]

  • Text

[embed]

  • Consequently slate value is a tree.
  • All nodes that present in value are rendered by the Editable component. We can specify the renderElement function to define each element's appearance.

Good start, letโ€™s continue with exploring dnd-kit.

dnd-kit

This toolkit is really useful for building Drag and Drop interfaces. It provides nice primitives to build your own dnd logic maximum customizable way. You can find all information here: https://dndkit.com/

Few words about how it is supposed to be applied in the app. It provides the following API:

  • DndContext
  • useDraggable
  • useDroppable

We can wrap dnd area into DndContext, then inside this area apply useDraggable hook to draggable elements and useDroppable hook to droppable elements.

But we wonโ€™t use it this way for sorting because dnd-kit already provides higher level API for it:

  • SortableContext
  • useSortable

One more component we need is:

  • DragOverlay. This component will be rendered on document body level and next to the mouse cursor temporarily while dragging.

Letโ€™s show how we can use it. This example is intended to demonstrate how dnd-kit works itself, without slate.js. You can see how components related to each other:

[embed]Dnd Kit Code Example

sandbox: https://codesandbox.io/s/dnd-kit-4rs8rz

deps: yarn add @dnd-kit/core @dnd-kit/sortable

You might notice, there is a Sortable component I didn't mention before. It is a simple component that applies sortable props to div. The props like transition and transform. You can find its implementation in the sandbox.

There is also a button component that we use like a dnd handle by applying listeners to it.

slate.js + dnd-kit

I hope after the previous parts you become a bit more familiar with these libraries in case you havenโ€™t used them before. Itโ€™s time to combine them.

Generally we need to do the following steps:

  • Wrap Editable into DndContext and SortableContext
  • Adjust renderElement function only for top level elements. We will render SortableElement component with useSortable hook inside.
  • For DndOverlay create DndOverlayContent component with temporary slate editor, that renders just one dragging element.

The code is here:

[embed]Slate.js + Dnd Kit Code Example

sandbox: https://codesandbox.io/s/slate-dnd-kit-brld4z

deps: yarn add nanoid slate slate-react @dnd-kit/core @dnd-kit/sortable

styled example: https://codesandbox.io/s/slate-dnd-kit-styled-7qjxm3

Assigning ids to new nodes

This is necessary to have unique ids for each sorting element. We pass an array of ids into SortableContext with items prop. And we also pass an id for each element to useSortable hook. Creating new elements is a process that slate does by itself. For example, when the Enter key is pressed. However, we can add a plugin that assigns unique ids for new elements. You can find the withNodeId plugin in the sandbox above.

Last part

As I said before this post is intended to share an idea. It might require way more coding to fix all possible issues and make it work perfectly in production. If you didnโ€™t use these libraries before, keep in mind, both libraries are in beta. However, it might be brought to a well level user experience.

I hope you find it useful. If you have any questions feel free to ask. I would also like to receive your feedback. And if you implement similar functionality the same or different way, please share it. It is really interesting for me. Thanks!

Originally published at https://dev.to on June 4, 2022.

Cover Image

Cover Image


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
f5c31f753425
slug
slate-js-dnd-kit-improving-rich-text-editor-ux-by-adding-drag-and-drop-f5c31f753425
url
https://medium.com/@devterminal/slate-js-dnd-kit-improving-rich-text-editor-ux-by-adding-drag-and-drop-f5c31f753425
canonical_url
https://medium.com/@devterminal/slate-js-dnd-kit-improving-rich-text-editor-ux-by-adding-drag-and-drop-f5c31f753425
author_url
https://medium.com/@devterminal
status
ok
fetched_at
2026-07-27 01:10:15