DEV Community

Cover image for Simplest Drag and Drop setup in React, in 10 lines of code with SortableJS
Arnaud Ambroselli
Arnaud Ambroselli

Posted on

Simplest Drag and Drop setup in React, in 10 lines of code with SortableJS

TDLR

SortableJS make things really easy !
For those who just want the final result, here is the code and a demo just below

Code

import React, { useState, useEffect, useRef } from 'react';
import Sortable from 'sortablejs';
import './style.css';

const initData = Array.from({ length: 15 }, (_, i) => ({
  _id: (i + 1).toString(),
  content: (i + 1).toString(),
}));

const SortableGrid = () => {
  const gridRef = useRef(null);
  const sortableJsRef = useRef(null);

  const [data, setData] = useState(JSON.parse(sessionStorage.getItem('my-grid')) || initData);

  const onListChange = () => {
    const newData = [...gridRef.current.children]
      .map(i => i.dataset.id)
      .map(id => data.find(item => item._id === id));

    sessionStorage.setItem('my-grid', JSON.stringify(newData));
    setData(data);
  };

  useEffect(() => {
    sortableJsRef.current = new Sortable(gridRef.current, {
      animation: 150,
      onEnd: onListChange,
    });
  }, []);

  return (
    <div ref={gridRef} id="gridDemo">
      {data.map(({ _id, content }) => (
        <div key={_id} data-id={_id} className="grid-square">
          {content}
        </div>
      ))}
    </div>
  );
};

export default SortableGrid;
Enter fullscreen mode Exit fullscreen mode

Demo

Demo available on my personal blog.

So many DragNDrop libs out int the react ecosystem...

...and yet no easy solution for any of them !

This library continues to be relied upon heavily by Atlassian products, but we are focused on other priorities right now and have no current plans for further feature development or improvements.

and also, not so easy to setup for someone who just want easy drag and drop

  • React Grid Layout: quite easy to setup, and quite powerful also. But I wanted to be able to move items in a grid so that it takes the position of another item in the grid and the grid keeps the same shape at the end of the drag/drop action - the defauilt behavior of this lib being to "make space" for the dragged item and break the grid layout. After spending one hour on it, I still couldn't find the way to achieve my goal, I quit.

-React DND: it seems also a powerful lib, but the API is sooooo ccomplicated ! And you have to read their tutorial to setup anything, which is also giving headaches... I tried to implement the API, but after 200 lines of coding and 1 hours spent, I was lost, I tried something else

-react-draggable: I must say I didn't see that one, and didn't try.

-react-grid-dnd: it looked like an easy setup and exactly want I was looking for, but... it's not maintained, and not working with npm7+ because it has react 16 as a dependency. So I had all the code setup before installing the lib, and I was quite fed up and tired when I discovered I would need to change my npm version to use it, or do some tricks here and there...

-react-sortablejs: I didn't try because it says as an introduction

Please note that this is not considered ready for production, as there are still a number of bugs being sent through.

Then I thought : damn, there should be out there a JavaScript library doing the simple thing I've asked for ! And I saw in this last react-sortablejs that it was a "React bindings to SortableJS".

I went to look for SortableJS, clicked on the demo, scrolled to the grid example which was doing exactly the simple stuff I was looking for.

I checked in the dev tools, there was nothing else than a div#gridDemo and some div.square-items inside. I checkd for gridDemo in the source code, and found out the code for that example:

// Grid demo
new Sortable(gridDemo, {
  animation: 150,
  ghostClass: 'blue-background-class',
});
Enter fullscreen mode Exit fullscreen mode

I couldn't believe it... only those three lines of code and that's it ?
And the api looks straight forward too : the onEnd function seems doing the job I needed.

I had to try it by myself !

Start with a simple grid, and just add a few more lines

I wrote the React initial code : an array of items display in a grid layout.

import React, { useState, useEffect, useRef } from 'react';
import Sortable from 'sortablejs';
import './style.css';

const initData = Array.from({ length: 15 }, (_, i) => ({
  _id: (i + 1).toString(),
  content: (i + 1).toString(),
}));

const SortableGrid = () => {
  const [data, setData] = useState(initData);

  return (
    <div id="gridDemo">
      {data.map(({ _id, content }) => (
        <div key={_id} data-id={_id} className="grid-square">
          {content}
        </div>
      ))}
    </div>
  );
};

export default SortableGrid;
Enter fullscreen mode Exit fullscreen mode

I then just added:

  • one ref for the grid container
  • one ref for the SortableJS element
  • one Effect to initiate SortableJs
  • one function to handle the drag and drop
  • data-id to all of the items in the grid layout
  • a bit of refacto to save the new layout in storage (or in your back-end most probably)

so that the code would be the one I wrote at the beginning, and as you can see, it works !

Discussion (0)