It all started out very simply: I was asked to make it possible for users to trade photos in the gallery. What surprised me when I learned that mobile phone browsers don't have drag & drop (DnD) built in? When I looked at the source, my project was the only one that used DnD. And I decided, for some reason, that my job was similar to the one already done. But it wasn't quite that easy.

React-beautiful-dnd

The previous implementation was for Y-axis DnD, and it doesn’t work well for the grid.

But at the moment when I realized this, it was already necessary to implement the feature. And I decided to do it simply, following the example of react-beautiful-dnd-grid. In fact, it's just splitting a one-dimensional array into chunks, and then the work goes on as with many one-dimensional arrays.

A short intro to react-beautiful-dnd

React's beautiful DND consists of several base components.

Basic usage is with X-axis DnD.

My implementation was just an extension of this behavior, split images into chunks, then every chunk is a row (which is Dropzone), and every image is draggable. When I handle the onDragEnd event in DragContext, I just map the row (chunk) index and the index in a row to a one-dimensional array index.:

const originalIndex = destinationChunkIndex * maxItems + indexInChunk + (sourceChunkIndex < destinationChunkIndex ? -1 : 0);

Everything was implemented, and the feature has already been under the radar for a couple of weeks, but then it was time for a design review, and they tell me that everything is bullshit. Revert it.

In fact, the main problem was that if such a solution looks good with columns, then there are small problems with rows. For example, the fact that photos fly off the screen and, in general, there is no feeling that this is how it should be

If you want, you can play on my playground. It’s possible that such a solution will be suitable for your case. https://codesandbox.io/p/github/pivaszbs/image-reordering-beautiful-dnd/draft/gifted-voice

So I understand that I need a real grid realization that looks like this, so I decided to continue research.

Polyfill realization

Next, I implemented the feature on the desktop, and everything was very easy there because of the browser support for DnD, so I thought, why not use a polyfill?

https://www.npmjs.com/package/mobile-drag-drop?embedable=true

But then a surprise was waiting for me with the fact that the ondragover event was not supported in this polyfill, and I could not swap the pictures when the user moved them without additional implementation or working with it by hand. So I decided to skip this variant to save time.

DnD kit

It would seem that my existence is in vain and that I will never succeed. But the moment of truth came, and I saw a notification about a wonderful library on one of the channels in Telegram.

https://dndkit.com/?embedable=true

I was happy, looking at the size of the library and how beautifully the examples are implemented in the documentation. I immediately went to look at the examples on the playground. In addition to DnD support for grids, the library also supports accessibility and is very customizable.

A short intro to DnD-kit

I don’t want to observe everything, just the things that are needed for understanding my solution to this problem. I will observe SortableContext, useSortable, DragOverlay, and useSensors, but it is an abstraction over primitives. DndContext, useDroppable, useDraggable (familiar words: it looks the same as react-beautiful-dnd but uses hooks instead of the render children pattern). If you want to know about primitives, look at the docs

Real-grid DnD implementation

This example was perfect for me, so I could look at the sources.

https://codesandbox.io/p/github/pivaszbs/image-reordering-beautiful-dnd/draft/gifted-voice

However, it was long and difficult to mess with the sources, so I went back to the board.

Step 1

According to the docs https://docs.dndkit.com/presets/sortable I made a small example with pictures.

https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-w0wlnh?file=%2Fsrc%2FApp.tsx

Step 2

Then I realized that the UX without delay is a so-so story and added activation constraints.

https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-w0wlnh?file=%2Fsrc%2FApp.tsx

Step 3

However, it just didn't take off, and a context menu popped up in Safari.

So I added user-select: none

https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-dwi8cb?file=%2Fsrc%2FImage.tsx

Step 4

Then I needed DragOverlay in order for the user to understand where his picture would be.

https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-revjso?file=%2Fsrc%2FApp.tsx

Step 5

Next, I decided that it's worth trying to describe how, in the examples, to make the component sortable so that you can reuse abstraction instead of primitives. It was quite hard, but right now it’s better than in examples.

https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-ssnzd2?file=%2Fsrc%2FApp.tsx

Conclusion

I am very glad that you have come this far with me. I hope I was able to save you time (it was not an easy but interesting way). I think the future belongs to libraries like dnd-kit, with their small size, good tree-shaking, and customization. I think libraries like react-dnd and react-beautiful-dnd will become a thing of the past. Thank you for your time!

Useful links

  1. https://dndkit.com/
  2. https://docs.dndkit.com/
  3. https://master--5fc05e08a4a65d0021ae0bf2.chromatic.com/?path=/story/presets-sortable-grid--basic-setup
  4. https://github.com/react-dnd/react-dnd
  5. https://github.com/atlassian/react-beautiful-dnd
  6. https://www.npmjs.com/package/mobile-drag-drop

All sandboxes, step by step

  1. https://codesandbox.io/p/github/pivaszbs/image-reordering-beautiful-dnd/draft/gifted-voice
  2. https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-w0wlnh?file=%2Fsrc%2FApp.tsx
  3. https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-1thxdp?file=%2Fsrc%2FApp.tsx
  4. https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-dwi8cb?file=%2Fsrc%2FImage.tsx
  5. https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-forked-revjso?file=%2Fsrc%2FApp.tsx
  6. https://codesandbox.io/p/sandbox/react-image-reordering-grid-mobile-ssnzd2?file=%2Fsrc%2FApp.tsx