reactjslistdrag-and-droplistitemreact-beautiful-dnd

React Beautiful DnD- set the drag handle to be ONLY the list item MARKER


I am using React Beautiful DnD to create a nested list. I know this is not supported by the library, but I've seen plenty of workarounds and my use-case is relatively simple (no dragging sub-list elements between parent lists; sub-list elements can only be dragged within their respective sub-list).

The issue is as follows: trying to drag elements from the nested list sometimes drags the parent list elements instead. (I just made a long post documenting my problem here.)

I haven't gotten any responses yet, so I stared thinking about other ways to potentially solve the problem. I realized one solution could be choosing only a specific area of each list element that can be clicked to drag, and making sure this area does not overlap between the parent/nested lists.

Seeing that this is possible here, I simply need to add {...provided.dragHandleProps} to the element that I want to serve as the drag handle.

However, my nested list is built using two instantiations of a reusable DnDList component that I wrote, so it gets a little more complicated. Rather than trying to figure out how to specify a drag handle as props, I'd like to just set the drag handle to be list item marker for each list item (the '1', '2', '3', etc next to each list item).

How can I add {...provided.dragHandleProps} to the li::marker elements of my list?


Solution

  • Here's how I figured it out:

    I ultimately used CSS to turn off the list item marker (listStyle: "none"), then wrapped each DnDList item in a flex container with a clickable drag icon that I manually placed on the left of the list item (first sibling in the flex container).

    I also overlayed an invisible div over the drag icon, and placed the {...provided.dragHandleProps} here. It looked like this:

    <div className={classes.listItemWrapper}>
      <div
        className={invisibleDiv}
        {...provided.dragHandleProps} // MUST CLICK THIS TO DRAG
      >
        <DragIndicatorIcon className={classes.dragIcon} />
      </div>
      {child}
     </div>
    

    Here is what the styling looked like (using material UI):

    listItemWrapper: {
    display: "flex",
    position: "relative",
    },
    invisibleDiv: {
      position: "absolute",
      left: "-4%",
      top: "36%",
      width: "40px",
      height: "40px",
      textAlign: "center",
    },
    

    Hope this is useful for somone!